VirtualBox

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

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

Main: new VirtualBox::ComposeMachineFilename() API; remove the 'default hard disk folder' concept and related APIs; GUI wizards need fixing

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette