VirtualBox

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

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

Main-OVF: make it possible to overwrite all available items if a vbox.xml is
present; use the defaults from the vbox.xml if present

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