VirtualBox

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

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

Main: move include statement

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