VirtualBox

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

Last change on this file since 31570 was 31562, checked in by vboxsync, 14 years ago

Main: merge IVirtualBox::FindHardDisk, GetHardDisk, FindDVDImage, GetDVDImage, FindFloppyImage and GetFloppyImage into one IVirtualBox::findMedium method

  • 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 31562 2010-08-11 10:02:40Z 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), &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), 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 * Little shortcut to SystemProperties::DefaultHardDiskFolder.
635 * @param str
636 * @return
637 */
638HRESULT Appliance::getDefaultHardDiskFolder(Utf8Str &str) const
639{
640 /* We need the default path for storing disk images */
641 ComPtr<ISystemProperties> systemProps;
642 HRESULT rc = mVirtualBox->COMGETTER(SystemProperties)(systemProps.asOutParam());
643 if (FAILED(rc)) return rc;
644 Bstr bstrDefaultHardDiskFolder;
645 rc = systemProps->COMGETTER(DefaultHardDiskFolder)(bstrDefaultHardDiskFolder.asOutParam());
646 if (FAILED(rc)) return rc;
647 str = bstrDefaultHardDiskFolder;
648
649 return S_OK;
650}
651
652/**
653 * Called from the import and export background threads to synchronize the second
654 * background disk thread's progress object with the current progress object so
655 * that the user interface sees progress correctly and that cancel signals are
656 * passed on to the second thread.
657 * @param pProgressThis Progress object of the current thread.
658 * @param pProgressAsync Progress object of asynchronous task running in background.
659 */
660void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
661 ComPtr<IProgress> &pProgressAsync)
662{
663 HRESULT rc;
664
665 // now loop until the asynchronous operation completes and then report its result
666 BOOL fCompleted;
667 BOOL fCanceled;
668 ULONG currentPercent;
669 while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
670 {
671 rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
672 if (FAILED(rc)) throw rc;
673 if (fCanceled)
674 {
675 pProgressAsync->Cancel();
676 break;
677 }
678
679 rc = pProgressAsync->COMGETTER(Percent(&currentPercent));
680 if (FAILED(rc)) throw rc;
681 if (!pProgressThis.isNull())
682 pProgressThis->SetCurrentOperationProgress(currentPercent);
683 if (fCompleted)
684 break;
685
686 /* Make sure the loop is not too tight */
687 rc = pProgressAsync->WaitForCompletion(100);
688 if (FAILED(rc)) throw rc;
689 }
690 // report result of asynchronous operation
691 LONG iRc;
692 rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
693 if (FAILED(rc)) throw rc;
694
695
696 // if the thread of the progress object has an error, then
697 // retrieve the error info from there, or it'll be lost
698 if (FAILED(iRc))
699 {
700 ProgressErrorInfo info(pProgressAsync);
701 Utf8Str str(info.getText());
702 const char *pcsz = str.c_str();
703 HRESULT rc2 = setError(iRc, pcsz);
704 throw rc2;
705 }
706}
707
708void Appliance::addWarning(const char* aWarning, ...)
709{
710 va_list args;
711 va_start(args, aWarning);
712 Utf8StrFmtVA str(aWarning, args);
713 va_end(args);
714 m->llWarnings.push_back(str);
715}
716
717/**
718 * Refreshes the cDisks and ulTotalDisksMB members in the instance data.
719 * Requires that virtual system descriptions are present.
720 */
721void Appliance::disksWeight()
722{
723 m->ulTotalDisksMB = 0;
724 m->cDisks = 0;
725 // weigh the disk images according to their sizes
726 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
727 for (it = m->virtualSystemDescriptions.begin();
728 it != m->virtualSystemDescriptions.end();
729 ++it)
730 {
731 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
732 /* One for every hard disk of the Virtual System */
733 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
734 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
735 for (itH = avsdeHDs.begin();
736 itH != avsdeHDs.end();
737 ++itH)
738 {
739 const VirtualSystemDescriptionEntry *pHD = *itH;
740 m->ulTotalDisksMB += pHD->ulSizeMB;
741 ++m->cDisks;
742 }
743 }
744
745}
746
747/**
748 * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a
749 * progress object with the proper weights and maximum progress values.
750 *
751 * @param pProgress
752 * @param bstrDescription
753 * @param mode
754 * @return
755 */
756HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress,
757 const Bstr &bstrDescription,
758 SetUpProgressMode mode)
759{
760 HRESULT rc;
761
762 /* Create the progress object */
763 pProgress.createObject();
764
765 // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data)
766 disksWeight();
767
768 m->ulWeightForManifestOperation = 0;
769
770 ULONG cOperations;
771 ULONG ulTotalOperationsWeight;
772
773 cOperations = 1 // one for XML setup
774 + m->cDisks; // plus one per disk
775 if (m->ulTotalDisksMB)
776 {
777 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML
778 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
779 }
780 else
781 {
782 // no disks to export:
783 m->ulWeightForXmlOperation = 1;
784 ulTotalOperationsWeight = 1;
785 }
786
787 switch (mode)
788 {
789 case ImportFileNoManifest:
790 break;
791
792 case ImportFileWithManifest:
793 case WriteFile:
794 ++cOperations; // another one for creating the manifest
795
796 // assume that checking or creating the manifest will take 10% of the time it takes to export the disks
797 m->ulWeightForManifestOperation = m->ulTotalDisksMB / 10;
798 ulTotalOperationsWeight += m->ulWeightForManifestOperation;
799 break;
800
801 case ImportS3:
802 {
803 cOperations += 1 + 1; // another one for the manifest file & another one for the import
804 ulTotalOperationsWeight = m->ulTotalDisksMB;
805 if (!m->ulTotalDisksMB)
806 // no disks to export:
807 ulTotalOperationsWeight = 1;
808
809 ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import
810 ulTotalOperationsWeight += ulImportWeight;
811
812 m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */
813
814 ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init
815 ulTotalOperationsWeight += ulInitWeight;
816 }
817 break;
818
819 case WriteS3:
820 {
821 cOperations += 1 + 1; // another one for the mf & another one for temporary creation
822
823 if (m->ulTotalDisksMB)
824 {
825 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)
826 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
827 }
828 else
829 {
830 // no disks to export:
831 ulTotalOperationsWeight = 1;
832 m->ulWeightForXmlOperation = 1;
833 }
834 ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
835 ulTotalOperationsWeight += ulOVFCreationWeight;
836 }
837 break;
838 }
839
840 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n",
841 m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation));
842
843 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
844 bstrDescription,
845 TRUE /* aCancelable */,
846 cOperations, // ULONG cOperations,
847 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
848 bstrDescription, // CBSTR bstrFirstOperationDescription,
849 m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight,
850 return rc;
851}
852
853void Appliance::parseURI(Utf8Str strUri, LocationInfo &locInfo) const
854{
855 /* Check the URI for the protocol */
856 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
857 {
858 locInfo.storageType = VFSType_File;
859 strUri = strUri.substr(sizeof("file://") - 1);
860 }
861 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
862 {
863 locInfo.storageType = VFSType_S3;
864 strUri = strUri.substr(sizeof("SunCloud://") - 1);
865 }
866 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
867 {
868 locInfo.storageType = VFSType_S3;
869 strUri = strUri.substr(sizeof("S3://") - 1);
870 }
871 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
872 throw E_NOTIMPL;
873
874 /* Not necessary on a file based URI */
875 if (locInfo.storageType != VFSType_File)
876 {
877 size_t uppos = strUri.find("@"); /* username:password combo */
878 if (uppos != Utf8Str::npos)
879 {
880 locInfo.strUsername = strUri.substr(0, uppos);
881 strUri = strUri.substr(uppos + 1);
882 size_t upos = locInfo.strUsername.find(":");
883 if (upos != Utf8Str::npos)
884 {
885 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
886 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
887 }
888 }
889 size_t hpos = strUri.find("/"); /* hostname part */
890 if (hpos != Utf8Str::npos)
891 {
892 locInfo.strHostname = strUri.substr(0, hpos);
893 strUri = strUri.substr(hpos);
894 }
895 }
896
897 locInfo.strPath = strUri;
898}
899
900void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket)
901{
902 /* Buckets are S3 specific. So parse the bucket out of the file path */
903 if (!aPath.startsWith("/"))
904 throw setError(E_INVALIDARG,
905 tr("The path '%s' must start with /"), aPath.c_str());
906 size_t bpos = aPath.find("/", 1);
907 if (bpos != Utf8Str::npos)
908 {
909 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
910 aPath = aPath.substr(bpos); /* The rest of the file path */
911 }
912 /* If there is no bucket name provided reject it */
913 if (aBucket.isEmpty())
914 throw setError(E_INVALIDARG,
915 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
916}
917
918Utf8Str Appliance::manifestFileName(Utf8Str aPath) const
919{
920 /* Get the name part */
921 char *pszMfName = RTStrDup(RTPathFilename(aPath.c_str()));
922 /* Strip any extensions */
923 RTPathStripExt(pszMfName);
924 /* Path without the filename */
925 aPath.stripFilename();
926 /* Format the manifest path */
927 Utf8StrFmt strMfFile("%s/%s.mf", aPath.c_str(), pszMfName);
928 RTStrFree(pszMfName);
929 return strMfFile;
930}
931
932/**
933 *
934 * @return
935 */
936int Appliance::TaskOVF::startThread()
937{
938 int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOrExport, this,
939 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
940 "Appliance::Task");
941
942 if (RT_FAILURE(vrc))
943 return Appliance::setErrorStatic(E_FAIL,
944 Utf8StrFmt("Could not create OVF task thread (%Rrc)\n", vrc));
945
946 return S_OK;
947}
948
949/**
950 * Thread function for the thread started in Appliance::readImpl() and Appliance::importImpl()
951 * and Appliance::writeImpl().
952 * This will in turn call Appliance::readFS() or Appliance::readS3() or Appliance::importFS()
953 * or Appliance::importS3() or Appliance::writeFS() or Appliance::writeS3().
954 *
955 * @param aThread
956 * @param pvUser
957 */
958/* static */
959DECLCALLBACK(int) Appliance::taskThreadImportOrExport(RTTHREAD /* aThread */, void *pvUser)
960{
961 std::auto_ptr<TaskOVF> task(static_cast<TaskOVF*>(pvUser));
962 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
963
964 Appliance *pAppliance = task->pAppliance;
965
966 LogFlowFuncEnter();
967 LogFlowFunc(("Appliance %p\n", pAppliance));
968
969 HRESULT taskrc = S_OK;
970
971 switch (task->taskType)
972 {
973 case TaskOVF::Read:
974 if (task->locInfo.storageType == VFSType_File)
975 taskrc = pAppliance->readFS(task->locInfo);
976 else if (task->locInfo.storageType == VFSType_S3)
977 taskrc = pAppliance->readS3(task.get());
978 break;
979
980 case TaskOVF::Import:
981 if (task->locInfo.storageType == VFSType_File)
982 taskrc = pAppliance->importFS(task->locInfo, task->pProgress);
983 else if (task->locInfo.storageType == VFSType_S3)
984 taskrc = pAppliance->importS3(task.get());
985 break;
986
987 case TaskOVF::Write:
988 if (task->locInfo.storageType == VFSType_File)
989 taskrc = pAppliance->writeFS(task->locInfo, task->enFormat, task->pProgress);
990 else if (task->locInfo.storageType == VFSType_S3)
991 taskrc = pAppliance->writeS3(task.get());
992 break;
993 }
994
995 task->rc = taskrc;
996
997 if (!task->pProgress.isNull())
998 task->pProgress->notifyComplete(taskrc);
999
1000 LogFlowFuncLeave();
1001
1002 return VINF_SUCCESS;
1003}
1004
1005/* static */
1006int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
1007{
1008 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
1009
1010 if ( pTask
1011 && !pTask->pProgress.isNull())
1012 {
1013 BOOL fCanceled;
1014 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
1015 if (fCanceled)
1016 return -1;
1017 pTask->pProgress->SetCurrentOperationProgress(uPercent);
1018 }
1019 return VINF_SUCCESS;
1020}
1021
1022////////////////////////////////////////////////////////////////////////////////
1023//
1024// IVirtualSystemDescription constructor / destructor
1025//
1026////////////////////////////////////////////////////////////////////////////////
1027
1028DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
1029
1030/**
1031 * COM initializer.
1032 * @return
1033 */
1034HRESULT VirtualSystemDescription::init()
1035{
1036 /* Enclose the state transition NotReady->InInit->Ready */
1037 AutoInitSpan autoInitSpan(this);
1038 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1039
1040 /* Initialize data */
1041 m = new Data();
1042 m->pConfig = NULL;
1043
1044 /* Confirm a successful initialization */
1045 autoInitSpan.setSucceeded();
1046 return S_OK;
1047}
1048
1049/**
1050* COM uninitializer.
1051*/
1052
1053void VirtualSystemDescription::uninit()
1054{
1055 if (m->pConfig)
1056 delete m->pConfig;
1057 delete m;
1058 m = NULL;
1059}
1060
1061////////////////////////////////////////////////////////////////////////////////
1062//
1063// IVirtualSystemDescription public methods
1064//
1065////////////////////////////////////////////////////////////////////////////////
1066
1067/**
1068 * Public method implementation.
1069 * @param
1070 * @return
1071 */
1072STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
1073{
1074 if (!aCount)
1075 return E_POINTER;
1076
1077 AutoCaller autoCaller(this);
1078 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1079
1080 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1081
1082 *aCount = (ULONG)m->llDescriptions.size();
1083
1084 return S_OK;
1085}
1086
1087/**
1088 * Public method implementation.
1089 * @return
1090 */
1091STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1092 ComSafeArrayOut(BSTR, aRefs),
1093 ComSafeArrayOut(BSTR, aOrigValues),
1094 ComSafeArrayOut(BSTR, aVboxValues),
1095 ComSafeArrayOut(BSTR, aExtraConfigValues))
1096{
1097 if (ComSafeArrayOutIsNull(aTypes) ||
1098 ComSafeArrayOutIsNull(aRefs) ||
1099 ComSafeArrayOutIsNull(aOrigValues) ||
1100 ComSafeArrayOutIsNull(aVboxValues) ||
1101 ComSafeArrayOutIsNull(aExtraConfigValues))
1102 return E_POINTER;
1103
1104 AutoCaller autoCaller(this);
1105 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1106
1107 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1108
1109 ULONG c = (ULONG)m->llDescriptions.size();
1110 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1111 com::SafeArray<BSTR> sfaRefs(c);
1112 com::SafeArray<BSTR> sfaOrigValues(c);
1113 com::SafeArray<BSTR> sfaVboxValues(c);
1114 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1115
1116 list<VirtualSystemDescriptionEntry>::const_iterator it;
1117 size_t i = 0;
1118 for (it = m->llDescriptions.begin();
1119 it != m->llDescriptions.end();
1120 ++it, ++i)
1121 {
1122 const VirtualSystemDescriptionEntry &vsde = (*it);
1123
1124 sfaTypes[i] = vsde.type;
1125
1126 Bstr bstr = vsde.strRef;
1127 bstr.cloneTo(&sfaRefs[i]);
1128
1129 bstr = vsde.strOvf;
1130 bstr.cloneTo(&sfaOrigValues[i]);
1131
1132 bstr = vsde.strVboxCurrent;
1133 bstr.cloneTo(&sfaVboxValues[i]);
1134
1135 bstr = vsde.strExtraConfigCurrent;
1136 bstr.cloneTo(&sfaExtraConfigValues[i]);
1137 }
1138
1139 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1140 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1141 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1142 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1143 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1144
1145 return S_OK;
1146}
1147
1148/**
1149 * Public method implementation.
1150 * @return
1151 */
1152STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescriptionType_T aType,
1153 ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1154 ComSafeArrayOut(BSTR, aRefs),
1155 ComSafeArrayOut(BSTR, aOrigValues),
1156 ComSafeArrayOut(BSTR, aVboxValues),
1157 ComSafeArrayOut(BSTR, aExtraConfigValues))
1158{
1159 if (ComSafeArrayOutIsNull(aTypes) ||
1160 ComSafeArrayOutIsNull(aRefs) ||
1161 ComSafeArrayOutIsNull(aOrigValues) ||
1162 ComSafeArrayOutIsNull(aVboxValues) ||
1163 ComSafeArrayOutIsNull(aExtraConfigValues))
1164 return E_POINTER;
1165
1166 AutoCaller autoCaller(this);
1167 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1168
1169 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1170
1171 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1172 ULONG c = (ULONG)vsd.size();
1173 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1174 com::SafeArray<BSTR> sfaRefs(c);
1175 com::SafeArray<BSTR> sfaOrigValues(c);
1176 com::SafeArray<BSTR> sfaVboxValues(c);
1177 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1178
1179 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1180 size_t i = 0;
1181 for (it = vsd.begin();
1182 it != vsd.end();
1183 ++it, ++i)
1184 {
1185 const VirtualSystemDescriptionEntry *vsde = (*it);
1186
1187 sfaTypes[i] = vsde->type;
1188
1189 Bstr bstr = vsde->strRef;
1190 bstr.cloneTo(&sfaRefs[i]);
1191
1192 bstr = vsde->strOvf;
1193 bstr.cloneTo(&sfaOrigValues[i]);
1194
1195 bstr = vsde->strVboxCurrent;
1196 bstr.cloneTo(&sfaVboxValues[i]);
1197
1198 bstr = vsde->strExtraConfigCurrent;
1199 bstr.cloneTo(&sfaExtraConfigValues[i]);
1200 }
1201
1202 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1203 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1204 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1205 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1206 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1207
1208 return S_OK;
1209}
1210
1211/**
1212 * Public method implementation.
1213 * @return
1214 */
1215STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionType_T aType,
1216 VirtualSystemDescriptionValueType_T aWhich,
1217 ComSafeArrayOut(BSTR, aValues))
1218{
1219 if (ComSafeArrayOutIsNull(aValues))
1220 return E_POINTER;
1221
1222 AutoCaller autoCaller(this);
1223 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1224
1225 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1226
1227 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1228 com::SafeArray<BSTR> sfaValues((ULONG)vsd.size());
1229
1230 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1231 size_t i = 0;
1232 for (it = vsd.begin();
1233 it != vsd.end();
1234 ++it, ++i)
1235 {
1236 const VirtualSystemDescriptionEntry *vsde = (*it);
1237
1238 Bstr bstr;
1239 switch (aWhich)
1240 {
1241 case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
1242 case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
1243 case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVboxCurrent; break;
1244 case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfigCurrent; break;
1245 }
1246
1247 bstr.cloneTo(&sfaValues[i]);
1248 }
1249
1250 sfaValues.detachTo(ComSafeArrayOutArg(aValues));
1251
1252 return S_OK;
1253}
1254
1255/**
1256 * Public method implementation.
1257 * @return
1258 */
1259STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
1260 ComSafeArrayIn(IN_BSTR, argVboxValues),
1261 ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
1262{
1263#ifndef RT_OS_WINDOWS
1264 NOREF(aEnabledSize);
1265#endif /* RT_OS_WINDOWS */
1266
1267 CheckComArgSafeArrayNotNull(aEnabled);
1268 CheckComArgSafeArrayNotNull(argVboxValues);
1269 CheckComArgSafeArrayNotNull(argExtraConfigValues);
1270
1271 AutoCaller autoCaller(this);
1272 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1273
1274 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1275
1276 com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
1277 com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
1278 com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
1279
1280 if ( (sfaEnabled.size() != m->llDescriptions.size())
1281 || (sfaVboxValues.size() != m->llDescriptions.size())
1282 || (sfaExtraConfigValues.size() != m->llDescriptions.size())
1283 )
1284 return E_INVALIDARG;
1285
1286 list<VirtualSystemDescriptionEntry>::iterator it;
1287 size_t i = 0;
1288 for (it = m->llDescriptions.begin();
1289 it != m->llDescriptions.end();
1290 ++it, ++i)
1291 {
1292 VirtualSystemDescriptionEntry& vsde = *it;
1293
1294 if (sfaEnabled[i])
1295 {
1296 vsde.strVboxCurrent = sfaVboxValues[i];
1297 vsde.strExtraConfigCurrent = sfaExtraConfigValues[i];
1298 }
1299 else
1300 vsde.type = VirtualSystemDescriptionType_Ignore;
1301 }
1302
1303 return S_OK;
1304}
1305
1306/**
1307 * Public method implementation.
1308 * @return
1309 */
1310STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
1311 IN_BSTR aVboxValue,
1312 IN_BSTR aExtraConfigValue)
1313{
1314 AutoCaller autoCaller(this);
1315 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1316
1317 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1318
1319 addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
1320
1321 return S_OK;
1322}
1323
1324/**
1325 * Internal method; adds a new description item to the member list.
1326 * @param aType Type of description for the new item.
1327 * @param strRef Reference item; only used with hard disk controllers.
1328 * @param aOrigValue Corresponding original value from OVF.
1329 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
1330 * @param ulSizeMB Weight for IProgress
1331 * @param strExtraConfig Extra configuration; meaning dependent on type.
1332 */
1333void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
1334 const Utf8Str &strRef,
1335 const Utf8Str &aOvfValue,
1336 const Utf8Str &aVboxValue,
1337 uint32_t ulSizeMB,
1338 const Utf8Str &strExtraConfig /*= ""*/)
1339{
1340 VirtualSystemDescriptionEntry vsde;
1341 vsde.ulIndex = (uint32_t)m->llDescriptions.size(); // each entry gets an index so the client side can reference them
1342 vsde.type = aType;
1343 vsde.strRef = strRef;
1344 vsde.strOvf = aOvfValue;
1345 vsde.strVboxSuggested // remember original value
1346 = vsde.strVboxCurrent // and set current value which can be overridden by setFinalValues()
1347 = aVboxValue;
1348 vsde.strExtraConfigSuggested
1349 = vsde.strExtraConfigCurrent
1350 = strExtraConfig;
1351 vsde.ulSizeMB = ulSizeMB;
1352
1353 m->llDescriptions.push_back(vsde);
1354}
1355
1356/**
1357 * Private method; returns a list of description items containing all the items from the member
1358 * description items of this virtual system that match the given type.
1359 * @param aType
1360 * @return
1361 */
1362std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
1363{
1364 std::list<VirtualSystemDescriptionEntry*> vsd;
1365
1366 list<VirtualSystemDescriptionEntry>::iterator it;
1367 for (it = m->llDescriptions.begin();
1368 it != m->llDescriptions.end();
1369 ++it)
1370 {
1371 if (it->type == aType)
1372 vsd.push_back(&(*it));
1373 }
1374
1375 return vsd;
1376}
1377
1378/**
1379 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1380 * the given reference ID. Useful when needing the controller for a particular
1381 * virtual disk.
1382 * @param id
1383 * @return
1384 */
1385const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
1386{
1387 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1388 list<VirtualSystemDescriptionEntry>::const_iterator it;
1389 for (it = m->llDescriptions.begin();
1390 it != m->llDescriptions.end();
1391 ++it)
1392 {
1393 const VirtualSystemDescriptionEntry &d = *it;
1394 switch (d.type)
1395 {
1396 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1397 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1398 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1399 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1400 if (d.strRef == strRef)
1401 return &d;
1402 break;
1403 }
1404 }
1405
1406 return NULL;
1407}
1408
1409/**
1410 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1411 * contains a <vbox:Machine> element. This method then attempts to parse that and
1412 * create a MachineConfigFile instance from it which is stored in this instance data
1413 * and can then be used to create a machine.
1414 *
1415 * This must only be called once per instance.
1416 *
1417 * This rethrows all XML and logic errors from MachineConfigFile.
1418 *
1419 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1420 * DOM tree.
1421 */
1422void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmMachine)
1423{
1424 settings::MachineConfigFile *pConfig = NULL;
1425
1426 Assert(m->pConfig == NULL);
1427
1428 try
1429 {
1430 pConfig = new settings::MachineConfigFile(NULL);
1431 pConfig->importMachineXML(elmMachine);
1432
1433 m->pConfig = pConfig;
1434 }
1435 catch (...)
1436 {
1437 if (pConfig)
1438 delete pConfig;
1439 throw;
1440 }
1441}
1442
1443/**
1444 * Returns the machine config created by importVboxMachineXML() or NULL if there's none.
1445 * @return
1446 */
1447const settings::MachineConfigFile* VirtualSystemDescription::getMachineConfig() const
1448{
1449 return m->pConfig;
1450}
1451
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