VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/ApplianceImpl.cpp@ 40257

Last change on this file since 40257 was 39248, checked in by vboxsync, 13 years ago

Runtime: new guest OS type for Solaris 11
Frontends/VirtualBox: add new patterns for Solaris 11 guest OS type, reuse the icon
Frontends/VBoxManage: more details for "list ostypes"
Main/xml: make guest OS type in config file an arbitrary string (still validated/mapped in the old way in the settings code), remove hardcoded limit of 8 network adapters
Main/Global: move list of valid guest OS types into a single place, add function to get the network adapter limit for each chipset type
Main/Console+Machine+Snapshot+NetworkAdapter+Appliance+VirtualBox+Guest+SystemProperties: consistently use the appropriate network adapter limit so that ICH9 chipset can use 36 network adapters, adapt to cleaned up guest OS type handling, remove leftover rendundant guest OS mapping, whitespace
Network/NAT: release log message cosmetics, allow unlimited number of instances, fix maxconn clamping
Network/PCNet+VirtioNet+E1000: allow unlimited number of instances

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