VirtualBox

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

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

Main-OVF: Don't instantly break out of the loop on cancel. Let the async process gracefully finish.

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