VirtualBox

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

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

com/string: Remove bool conversion operator and other convenience error operators. They are hiding programming errors (like incorrect empty string checks, and in one case a free of the wrong pointer).

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