VirtualBox

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

Last change on this file since 82294 was 81422, checked in by vboxsync, 5 years ago

OCI: (bugref:9469) cloud network integration concept (disabled in Config.kmk).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.0 KB
Line 
1/* $Id: ApplianceImpl.cpp 81422 2019-10-21 18:04:10Z vboxsync $ */
2/** @file
3 * IAppliance and IVirtualSystem COM class implementations.
4 */
5
6/*
7 * Copyright (C) 2008-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MAIN_APPLIANCE
23#include <iprt/path.h>
24#include <iprt/cpp/path.h>
25#include <iprt/cpp/utils.h>
26#include <VBox/com/array.h>
27#include <map>
28
29#include "ApplianceImpl.h"
30#include "VFSExplorerImpl.h"
31#include "VirtualBoxImpl.h"
32#include "GuestOSTypeImpl.h"
33#include "Global.h"
34#include "ProgressImpl.h"
35#include "MachineImpl.h"
36#include "SystemPropertiesImpl.h"
37#include "AutoCaller.h"
38#include "LoggingNew.h"
39#include "CertificateImpl.h"
40
41#include "ApplianceImplPrivate.h"
42
43using namespace std;
44
45
46/*********************************************************************************************************************************
47* Global Variables *
48*********************************************************************************************************************************/
49static const char * const g_pszISOURI = "http://www.ecma-international.org/publications/standards/Ecma-119.htm";
50static const char * const g_pszVMDKStreamURI = "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized";
51static const char * const g_pszVMDKSparseURI = "http://www.vmware.com/specifications/vmdk.html#sparse";
52static const char * const g_pszVMDKCompressedURI = "http://www.vmware.com/specifications/vmdk.html#compressed";
53static const char * const g_pszVMDKCompressedURI2 = "http://www.vmware.com/interfaces/specifications/vmdk.html#compressed";
54static const char * const g_pszrVHDURI = "http://go.microsoft.com/fwlink/?LinkId=137171";
55static char g_szIsoBackend[128];
56static char g_szVmdkBackend[128];
57static char g_szVhdBackend[128];
58/** Set after the g_szXxxxBackend variables has been initialized. */
59static bool volatile g_fInitializedBackendNames = false;
60
61static struct
62{
63 const char *pszUri, *pszBackend;
64} const g_aUriToBackend[] =
65{
66 { g_pszISOURI, g_szIsoBackend },
67 { g_pszVMDKStreamURI, g_szVmdkBackend },
68 { g_pszVMDKSparseURI, g_szVmdkBackend },
69 { g_pszVMDKCompressedURI, g_szVmdkBackend },
70 { g_pszVMDKCompressedURI2, g_szVmdkBackend },
71 { g_pszrVHDURI, g_szVhdBackend },
72};
73
74static std::map<Utf8Str, Utf8Str> supportedStandardsURI;
75
76static struct
77{
78 ovf::CIMOSType_T cim;
79 VBOXOSTYPE osType;
80} const g_aOsTypes[] =
81{
82 { ovf::CIMOSType_CIMOS_Unknown, VBOXOSTYPE_Unknown },
83 { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS2 },
84 { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS2Warp3 },
85 { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS2Warp4 },
86 { ovf::CIMOSType_CIMOS_OS2, VBOXOSTYPE_OS2Warp45 },
87 { ovf::CIMOSType_CIMOS_MSDOS, VBOXOSTYPE_DOS },
88 { ovf::CIMOSType_CIMOS_WIN3x, VBOXOSTYPE_Win31 },
89 { ovf::CIMOSType_CIMOS_WIN95, VBOXOSTYPE_Win95 },
90 { ovf::CIMOSType_CIMOS_WIN98, VBOXOSTYPE_Win98 },
91 { ovf::CIMOSType_CIMOS_WINNT, VBOXOSTYPE_WinNT },
92 { ovf::CIMOSType_CIMOS_WINNT, VBOXOSTYPE_WinNT4 },
93 { ovf::CIMOSType_CIMOS_WINNT, VBOXOSTYPE_WinNT3x },
94 { ovf::CIMOSType_CIMOS_NetWare, VBOXOSTYPE_Netware },
95 { ovf::CIMOSType_CIMOS_NovellOES, VBOXOSTYPE_Netware },
96 { ovf::CIMOSType_CIMOS_Solaris, VBOXOSTYPE_Solaris },
97 { ovf::CIMOSType_CIMOS_SunOS, VBOXOSTYPE_Solaris },
98 { ovf::CIMOSType_CIMOS_FreeBSD, VBOXOSTYPE_FreeBSD },
99 { ovf::CIMOSType_CIMOS_NetBSD, VBOXOSTYPE_NetBSD },
100 { ovf::CIMOSType_CIMOS_QNX, VBOXOSTYPE_QNX },
101 { ovf::CIMOSType_CIMOS_Windows2000, VBOXOSTYPE_Win2k },
102 { ovf::CIMOSType_CIMOS_WindowsMe, VBOXOSTYPE_WinMe },
103 { ovf::CIMOSType_CIMOS_OpenBSD, VBOXOSTYPE_OpenBSD },
104 { ovf::CIMOSType_CIMOS_WindowsXP, VBOXOSTYPE_WinXP },
105 { ovf::CIMOSType_CIMOS_WindowsXPEmbedded, VBOXOSTYPE_WinXP },
106 { ovf::CIMOSType_CIMOS_WindowsEmbeddedforPointofService, VBOXOSTYPE_WinXP },
107 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003, VBOXOSTYPE_Win2k3 },
108 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003_64, VBOXOSTYPE_Win2k3_x64 },
109 { ovf::CIMOSType_CIMOS_WindowsXP_64, VBOXOSTYPE_WinXP_x64 },
110 { ovf::CIMOSType_CIMOS_WindowsVista, VBOXOSTYPE_WinVista },
111 { ovf::CIMOSType_CIMOS_WindowsVista_64, VBOXOSTYPE_WinVista_x64 },
112 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008, VBOXOSTYPE_Win2k8 },
113 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008_64, VBOXOSTYPE_Win2k8_x64 },
114 { ovf::CIMOSType_CIMOS_FreeBSD_64, VBOXOSTYPE_FreeBSD_x64 },
115 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS },
116 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS_x64 }, // there is no CIM 64-bit type for this
117 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS106 },
118 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS106_x64 },
119 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS107_x64 },
120 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS108_x64 },
121 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS109_x64 },
122 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS1010_x64 },
123 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS1011_x64 },
124 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS1012_x64 },
125 { ovf::CIMOSType_CIMOS_MACOS, VBOXOSTYPE_MacOS1013_x64 },
126
127 // Linuxes
128 { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, VBOXOSTYPE_RedHat },
129 { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, VBOXOSTYPE_RedHat_x64 },
130 { ovf::CIMOSType_CIMOS_Solaris_64, VBOXOSTYPE_Solaris_x64 },
131 { ovf::CIMOSType_CIMOS_SUSE, VBOXOSTYPE_OpenSUSE },
132 { ovf::CIMOSType_CIMOS_SLES, VBOXOSTYPE_OpenSUSE },
133 { ovf::CIMOSType_CIMOS_NovellLinuxDesktop, VBOXOSTYPE_OpenSUSE },
134 { ovf::CIMOSType_CIMOS_SUSE_64, VBOXOSTYPE_OpenSUSE_x64 },
135 { ovf::CIMOSType_CIMOS_SLES_64, VBOXOSTYPE_OpenSUSE_x64 },
136 { ovf::CIMOSType_CIMOS_LINUX, VBOXOSTYPE_Linux },
137 { ovf::CIMOSType_CIMOS_LINUX, VBOXOSTYPE_Linux22 },
138 { ovf::CIMOSType_CIMOS_SunJavaDesktopSystem, VBOXOSTYPE_Linux },
139 { ovf::CIMOSType_CIMOS_TurboLinux, VBOXOSTYPE_Turbolinux },
140 { ovf::CIMOSType_CIMOS_TurboLinux_64, VBOXOSTYPE_Turbolinux_x64 },
141 { ovf::CIMOSType_CIMOS_Mandriva, VBOXOSTYPE_Mandriva },
142 { ovf::CIMOSType_CIMOS_Mandriva_64, VBOXOSTYPE_Mandriva_x64 },
143 { ovf::CIMOSType_CIMOS_Ubuntu, VBOXOSTYPE_Ubuntu },
144 { ovf::CIMOSType_CIMOS_Ubuntu_64, VBOXOSTYPE_Ubuntu_x64 },
145 { ovf::CIMOSType_CIMOS_Debian, VBOXOSTYPE_Debian },
146 { ovf::CIMOSType_CIMOS_Debian_64, VBOXOSTYPE_Debian_x64 },
147 { ovf::CIMOSType_CIMOS_Linux_2_4_x, VBOXOSTYPE_Linux24 },
148 { ovf::CIMOSType_CIMOS_Linux_2_4_x_64, VBOXOSTYPE_Linux24_x64 },
149 { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_Linux26 },
150 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_Linux26_x64 },
151 { ovf::CIMOSType_CIMOS_Linux_64, VBOXOSTYPE_Linux26_x64 },
152
153 // types that we have support for but CIM doesn't
154 { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_ArchLinux },
155 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_ArchLinux_x64 },
156 { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_FedoraCore },
157 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_FedoraCore_x64 },
158 { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_Gentoo },
159 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_Gentoo_x64 },
160 { ovf::CIMOSType_CIMOS_Linux_2_6_x, VBOXOSTYPE_Xandros },
161 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, VBOXOSTYPE_Xandros_x64 },
162 { ovf::CIMOSType_CIMOS_Solaris, VBOXOSTYPE_OpenSolaris },
163 { ovf::CIMOSType_CIMOS_Solaris_64, VBOXOSTYPE_OpenSolaris_x64 },
164
165 // types added with CIM 2.25.0 follow:
166 { ovf::CIMOSType_CIMOS_WindowsServer2008R2, VBOXOSTYPE_Win2k8 }, // duplicate, see above
167// { ovf::CIMOSType_CIMOS_VMwareESXi = 104, // we can't run ESX in a VM
168 { ovf::CIMOSType_CIMOS_Windows7, VBOXOSTYPE_Win7 },
169 { ovf::CIMOSType_CIMOS_Windows7, VBOXOSTYPE_Win7_x64 }, // there is no
170 // CIM 64-bit type for this
171 { ovf::CIMOSType_CIMOS_CentOS, VBOXOSTYPE_RedHat },
172 { ovf::CIMOSType_CIMOS_CentOS_64, VBOXOSTYPE_RedHat_x64 },
173 { ovf::CIMOSType_CIMOS_OracleEnterpriseLinux, VBOXOSTYPE_Oracle },
174 { ovf::CIMOSType_CIMOS_OracleEnterpriseLinux_64, VBOXOSTYPE_Oracle_x64 },
175 { ovf::CIMOSType_CIMOS_eComStation, VBOXOSTYPE_ECS }
176
177 // there are no CIM types for these, so these turn to "other" on export:
178 // VBOXOSTYPE_OpenBSD
179 // VBOXOSTYPE_OpenBSD_x64
180 // VBOXOSTYPE_NetBSD
181 // VBOXOSTYPE_NetBSD_x64
182
183};
184
185/* Pattern structure for matching the OS type description field */
186struct osTypePattern
187{
188 const char *pcszPattern;
189 VBOXOSTYPE osType;
190};
191
192/* These are the 32-Bit ones. They are sorted by priority. */
193static const osTypePattern g_aOsTypesPattern[] =
194{
195 {"Windows NT", VBOXOSTYPE_WinNT4},
196 {"Windows XP", VBOXOSTYPE_WinXP},
197 {"Windows 2000", VBOXOSTYPE_Win2k},
198 {"Windows 2003", VBOXOSTYPE_Win2k3},
199 {"Windows Vista", VBOXOSTYPE_WinVista},
200 {"Windows 2008", VBOXOSTYPE_Win2k8},
201 {"SUSE", VBOXOSTYPE_OpenSUSE},
202 {"Novell", VBOXOSTYPE_OpenSUSE},
203 {"Red Hat", VBOXOSTYPE_RedHat},
204 {"Mandriva", VBOXOSTYPE_Mandriva},
205 {"Ubuntu", VBOXOSTYPE_Ubuntu},
206 {"Debian", VBOXOSTYPE_Debian},
207 {"QNX", VBOXOSTYPE_QNX},
208 {"Linux 2.4", VBOXOSTYPE_Linux24},
209 {"Linux 2.6", VBOXOSTYPE_Linux26},
210 {"Linux", VBOXOSTYPE_Linux},
211 {"OpenSolaris", VBOXOSTYPE_OpenSolaris},
212 {"Solaris", VBOXOSTYPE_OpenSolaris},
213 {"FreeBSD", VBOXOSTYPE_FreeBSD},
214 {"NetBSD", VBOXOSTYPE_NetBSD},
215 {"Windows 95", VBOXOSTYPE_Win95},
216 {"Windows 98", VBOXOSTYPE_Win98},
217 {"Windows Me", VBOXOSTYPE_WinMe},
218 {"Windows 3.", VBOXOSTYPE_Win31},
219 {"DOS", VBOXOSTYPE_DOS},
220 {"OS2", VBOXOSTYPE_OS2}
221};
222
223/* These are the 64-Bit ones. They are sorted by priority. */
224static const osTypePattern g_aOsTypesPattern64[] =
225{
226 {"Windows XP", VBOXOSTYPE_WinXP_x64},
227 {"Windows 2003", VBOXOSTYPE_Win2k3_x64},
228 {"Windows Vista", VBOXOSTYPE_WinVista_x64},
229 {"Windows 2008", VBOXOSTYPE_Win2k8_x64},
230 {"SUSE", VBOXOSTYPE_OpenSUSE_x64},
231 {"Novell", VBOXOSTYPE_OpenSUSE_x64},
232 {"Red Hat", VBOXOSTYPE_RedHat_x64},
233 {"Mandriva", VBOXOSTYPE_Mandriva_x64},
234 {"Ubuntu", VBOXOSTYPE_Ubuntu_x64},
235 {"Debian", VBOXOSTYPE_Debian_x64},
236 {"Linux 2.4", VBOXOSTYPE_Linux24_x64},
237 {"Linux 2.6", VBOXOSTYPE_Linux26_x64},
238 {"Linux", VBOXOSTYPE_Linux26_x64},
239 {"OpenSolaris", VBOXOSTYPE_OpenSolaris_x64},
240 {"Solaris", VBOXOSTYPE_OpenSolaris_x64},
241 {"FreeBSD", VBOXOSTYPE_FreeBSD_x64},
242};
243
244/**
245 * Private helper func that suggests a VirtualBox guest OS type
246 * for the given OVF operating system type.
247 */
248void convertCIMOSType2VBoxOSType(Utf8Str &strType, ovf::CIMOSType_T c, const Utf8Str &cStr)
249{
250 /* First check if the type is other/other_64 */
251 if (c == ovf::CIMOSType_CIMOS_Other)
252 {
253 for (size_t i = 0; i < RT_ELEMENTS(g_aOsTypesPattern); ++i)
254 if (cStr.contains(g_aOsTypesPattern[i].pcszPattern, Utf8Str::CaseInsensitive))
255 {
256 strType = Global::OSTypeId(g_aOsTypesPattern[i].osType);
257 return;
258 }
259 }
260 else if (c == ovf::CIMOSType_CIMOS_Other_64)
261 {
262 for (size_t i = 0; i < RT_ELEMENTS(g_aOsTypesPattern64); ++i)
263 if (cStr.contains(g_aOsTypesPattern64[i].pcszPattern, Utf8Str::CaseInsensitive))
264 {
265 strType = Global::OSTypeId(g_aOsTypesPattern64[i].osType);
266 return;
267 }
268 }
269
270 for (size_t i = 0; i < RT_ELEMENTS(g_aOsTypes); ++i)
271 {
272 if (c == g_aOsTypes[i].cim)
273 {
274 strType = Global::OSTypeId(g_aOsTypes[i].osType);
275 return;
276 }
277 }
278
279 if (c == ovf::CIMOSType_CIMOS_Other_64)
280 strType = Global::OSTypeId(VBOXOSTYPE_Unknown_x64);
281 else
282 strType = Global::OSTypeId(VBOXOSTYPE_Unknown);
283}
284
285/**
286 * Private helper func that suggests a VirtualBox guest OS type
287 * for the given OVF operating system type.
288 * @returns CIM OS type.
289 * @param pcszVBox Our guest OS type identifier string.
290 * @param fLongMode Whether long mode is enabled and a 64-bit CIM type is
291 * preferred even if the VBox guest type isn't 64-bit.
292 */
293ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVBox, BOOL fLongMode)
294{
295 for (size_t i = 0; i < RT_ELEMENTS(g_aOsTypes); ++i)
296 {
297 if (!RTStrICmp(pcszVBox, Global::OSTypeId(g_aOsTypes[i].osType)))
298 {
299 if (fLongMode && !(g_aOsTypes[i].osType & VBOXOSTYPE_x64))
300 {
301 VBOXOSTYPE enmDesiredOsType = (VBOXOSTYPE)((int)g_aOsTypes[i].osType | (int)VBOXOSTYPE_x64);
302 size_t j = i;
303 while (++j < RT_ELEMENTS(g_aOsTypes))
304 if (g_aOsTypes[j].osType == enmDesiredOsType)
305 return g_aOsTypes[j].cim;
306 j = i;
307 while (--j > 0)
308 if (g_aOsTypes[j].osType == enmDesiredOsType)
309 return g_aOsTypes[j].cim;
310 /* Not all OSes have 64-bit versions, so just return the 32-bit variant. */
311 }
312 return g_aOsTypes[i].cim;
313 }
314 }
315
316 return fLongMode ? ovf::CIMOSType_CIMOS_Other_64 : ovf::CIMOSType_CIMOS_Other;
317}
318
319Utf8Str convertNetworkAttachmentTypeToString(NetworkAttachmentType_T type)
320{
321 Utf8Str strType;
322 switch (type)
323 {
324 case NetworkAttachmentType_NAT: strType = "NAT"; break;
325 case NetworkAttachmentType_Bridged: strType = "Bridged"; break;
326 case NetworkAttachmentType_Internal: strType = "Internal"; break;
327 case NetworkAttachmentType_HostOnly: strType = "HostOnly"; break;
328 case NetworkAttachmentType_Generic: strType = "Generic"; break;
329 case NetworkAttachmentType_NATNetwork: strType = "NATNetwork"; break;
330 case NetworkAttachmentType_Null: strType = "Null"; break;
331 case NetworkAttachmentType_Cloud: strType = "Cloud"; break;
332#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
333 case NetworkAttachmentType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
334#endif
335 }
336 return strType;
337}
338
339
340////////////////////////////////////////////////////////////////////////////////
341//
342// Appliance constructor / destructor
343//
344// ////////////////////////////////////////////////////////////////////////////////
345
346DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
347
348HRESULT VirtualSystemDescription::FinalConstruct()
349{
350 return BaseFinalConstruct();
351}
352
353void VirtualSystemDescription::FinalRelease()
354{
355 uninit();
356
357 BaseFinalRelease();
358}
359
360Appliance::Appliance()
361 : mVirtualBox(NULL)
362{
363}
364
365Appliance::~Appliance()
366{
367}
368
369
370HRESULT Appliance::FinalConstruct()
371{
372 return BaseFinalConstruct();
373}
374
375void Appliance::FinalRelease()
376{
377 uninit();
378
379 BaseFinalRelease();
380}
381
382
383////////////////////////////////////////////////////////////////////////////////
384//
385// Internal helpers
386//
387////////////////////////////////////////////////////////////////////////////////
388
389
390////////////////////////////////////////////////////////////////////////////////
391//
392// IVirtualBox public methods
393//
394////////////////////////////////////////////////////////////////////////////////
395
396// This code is here so we won't have to include the appliance headers in the
397// IVirtualBox implementation.
398
399/**
400 * Implementation for IVirtualBox::createAppliance.
401 *
402 * @param aAppliance IAppliance object created if S_OK is returned.
403 * @return S_OK or error.
404 */
405HRESULT VirtualBox::createAppliance(ComPtr<IAppliance> &aAppliance)
406{
407 ComObjPtr<Appliance> appliance;
408 HRESULT hrc = appliance.createObject();
409 if (SUCCEEDED(hrc))
410 {
411 hrc = appliance->init(this);
412 if (SUCCEEDED(hrc))
413 hrc = appliance.queryInterfaceTo(aAppliance.asOutParam());
414 }
415 return hrc;
416}
417
418/**
419 * Appliance COM initializer.
420 * @param aVirtualBox The VirtualBox object.
421 */
422HRESULT Appliance::init(VirtualBox *aVirtualBox)
423{
424 HRESULT rc = S_OK;
425 /* Enclose the state transition NotReady->InInit->Ready */
426 AutoInitSpan autoInitSpan(this);
427 AssertReturn(autoInitSpan.isOk(), E_FAIL);
428
429 /* Weak reference to a VirtualBox object */
430 unconst(mVirtualBox) = aVirtualBox;
431
432 // initialize data
433 m = new Data;
434 m->m_pSecretKeyStore = new SecretKeyStore(false /* fRequireNonPageable*/);
435 AssertReturn(m->m_pSecretKeyStore, E_FAIL);
436
437 rc = i_initBackendNames();
438
439 /* Confirm a successful initialization */
440 autoInitSpan.setSucceeded();
441
442 return rc;
443}
444
445/**
446 * Appliance COM uninitializer.
447 */
448void Appliance::uninit()
449{
450 /* Enclose the state transition Ready->InUninit->NotReady */
451 AutoUninitSpan autoUninitSpan(this);
452 if (autoUninitSpan.uninitDone())
453 return;
454
455 if (m->m_pSecretKeyStore)
456 delete m->m_pSecretKeyStore;
457
458 delete m;
459 m = NULL;
460}
461
462////////////////////////////////////////////////////////////////////////////////
463//
464// IAppliance public methods
465//
466////////////////////////////////////////////////////////////////////////////////
467
468/**
469 * Public method implementation.
470 */
471HRESULT Appliance::getPath(com::Utf8Str &aPath)
472{
473 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
474
475 aPath = m->locInfo.strPath;
476
477 return S_OK;
478}
479
480/**
481 * Public method implementation.
482 */
483HRESULT Appliance::getDisks(std::vector<com::Utf8Str> &aDisks)
484{
485 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
486
487 aDisks.resize(0);
488
489 if (m->pReader) // OVFReader instantiated?
490 {
491 aDisks.resize(m->pReader->m_mapDisks.size());
492
493 ovf::DiskImagesMap::const_iterator it;
494 size_t i = 0;
495 for (it = m->pReader->m_mapDisks.begin();
496 it != m->pReader->m_mapDisks.end();
497 ++it, ++i)
498 {
499 // create a string representing this disk
500 const ovf::DiskImage &d = it->second;
501 char *psz = NULL;
502 RTStrAPrintf(&psz,
503 "%s\t"
504 "%RI64\t"
505 "%RI64\t"
506 "%s\t"
507 "%s\t"
508 "%RI64\t"
509 "%RI64\t"
510 "%s",
511 d.strDiskId.c_str(),
512 d.iCapacity,
513 d.iPopulatedSize,
514 d.strFormat.c_str(),
515 d.strHref.c_str(),
516 d.iSize,
517 d.iChunkSize,
518 d.strCompression.c_str());
519 Utf8Str utf(psz);
520 aDisks[i] = utf;
521 RTStrFree(psz);
522 }
523 }
524
525 return S_OK;
526}
527
528/**
529 * Public method implementation.
530 */
531HRESULT Appliance::getCertificate(ComPtr<ICertificate> &aCertificateInfo)
532{
533 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
534
535 /* Can be NULL at this point, queryInterfaceto handles that. */
536 m->ptrCertificateInfo.queryInterfaceTo(aCertificateInfo.asOutParam());
537 return S_OK;
538}
539
540/**
541 * Public method implementation.
542 */
543HRESULT Appliance::getVirtualSystemDescriptions(std::vector<ComPtr<IVirtualSystemDescription> > &aVirtualSystemDescriptions)
544{
545 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
546
547 aVirtualSystemDescriptions.resize(m->virtualSystemDescriptions.size());
548 std::list< ComObjPtr<VirtualSystemDescription> > vsds(m->virtualSystemDescriptions);
549 size_t i = 0;
550 for (std::list< ComObjPtr<VirtualSystemDescription> >::iterator it = vsds.begin(); it != vsds.end(); ++it, ++i)
551 {
552 (*it).queryInterfaceTo(aVirtualSystemDescriptions[i].asOutParam());
553 }
554 return S_OK;
555}
556
557/**
558 * Public method implementation.
559 */
560HRESULT Appliance::getMachines(std::vector<com::Utf8Str> &aMachines)
561{
562 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
563
564 aMachines.resize(m->llGuidsMachinesCreated.size());
565 size_t i = 0;
566 for (std::list<Guid>::const_iterator it = m->llGuidsMachinesCreated.begin();
567 it != m->llGuidsMachinesCreated.end();
568 ++it, ++i)
569 {
570 const Guid &uuid = *it;
571 aMachines[i] = uuid.toUtf16();
572 }
573 return S_OK;
574}
575
576HRESULT Appliance::createVFSExplorer(const com::Utf8Str &aURI, ComPtr<IVFSExplorer> &aExplorer)
577{
578 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
579
580 ComObjPtr<VFSExplorer> explorer;
581 HRESULT rc = S_OK;
582 try
583 {
584 Utf8Str uri(aURI);
585 /* Check which kind of export the user has requested */
586 LocationInfo li;
587 i_parseURI(aURI, li);
588 /* Create the explorer object */
589 explorer.createObject();
590 rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
591 }
592 catch (HRESULT aRC)
593 {
594 rc = aRC;
595 }
596
597 if (SUCCEEDED(rc))
598 /* Return explorer to the caller */
599 explorer.queryInterfaceTo(aExplorer.asOutParam());
600
601 return rc;
602}
603
604
605/**
606 * Public method implementation.
607 * Add the "aRequested" numbers of new empty objects of VSD into the list
608 * "virtualSystemDescriptions".
609 * The parameter "aCreated" keeps the actual number of the added objects.
610 * In case of exception all added objects are removed from the list.
611 */
612HRESULT Appliance::createVirtualSystemDescriptions(ULONG aRequested, ULONG *aCreated)
613{
614 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
615
616 HRESULT rc = S_OK;
617 uint32_t lQuantity = aRequested;
618 uint32_t i=0;
619
620 if (lQuantity < 1)
621 return setError(E_FAIL, tr("The number of VirtualSystemDescription objects must be at least 1 or more."));
622 try
623 {
624 for (; i<lQuantity; ++i)
625 {
626 ComObjPtr<VirtualSystemDescription> opVSD;
627 rc = opVSD.createObject();
628 if (SUCCEEDED(rc))
629 {
630 rc = opVSD->init();
631 if (SUCCEEDED(rc))
632 m->virtualSystemDescriptions.push_back(opVSD);
633 else
634 break;
635 }
636 else
637 break;
638 }
639
640 if (i<lQuantity)
641 LogRel(("Number of created VirtualSystemDescription objects is less than requested"
642 "(Requested %d, Created %d)",lQuantity, i));
643
644 *aCreated = i;
645 }
646 catch (HRESULT aRC)
647 {
648 for (; i>0; --i)
649 {
650 if (!m->virtualSystemDescriptions.empty())
651 m->virtualSystemDescriptions.pop_back();
652 else
653 break;
654 }
655 rc = aRC;
656 }
657
658 return rc;
659}
660
661/**
662 * Public method implementation.
663 */
664HRESULT Appliance::getWarnings(std::vector<com::Utf8Str> &aWarnings)
665{
666 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
667
668 aWarnings.resize(m->llWarnings.size());
669
670 list<Utf8Str>::const_iterator it;
671 size_t i = 0;
672 for (it = m->llWarnings.begin();
673 it != m->llWarnings.end();
674 ++it, ++i)
675 {
676 aWarnings[i] = *it;
677 }
678
679 return S_OK;
680}
681
682HRESULT Appliance::getPasswordIds(std::vector<com::Utf8Str> &aIdentifiers)
683{
684 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
685
686 aIdentifiers = m->m_vecPasswordIdentifiers;
687 return S_OK;
688}
689
690HRESULT Appliance::getMediumIdsForPasswordId(const com::Utf8Str &aPasswordId, std::vector<com::Guid> &aIdentifiers)
691{
692 HRESULT hrc = S_OK;
693 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
694
695 std::map<com::Utf8Str, GUIDVEC>::const_iterator it = m->m_mapPwIdToMediumIds.find(aPasswordId);
696 if (it != m->m_mapPwIdToMediumIds.end())
697 aIdentifiers = it->second;
698 else
699 hrc = setError(E_FAIL, tr("The given password identifier is not associated with any medium"));
700
701 return hrc;
702}
703
704HRESULT Appliance::addPasswords(const std::vector<com::Utf8Str> &aIdentifiers,
705 const std::vector<com::Utf8Str> &aPasswords)
706{
707 HRESULT hrc = S_OK;
708
709 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
710
711 /* Check that the IDs do not exist already before changing anything. */
712 for (unsigned i = 0; i < aIdentifiers.size(); i++)
713 {
714 SecretKey *pKey = NULL;
715 int rc = m->m_pSecretKeyStore->retainSecretKey(aIdentifiers[i], &pKey);
716 if (rc != VERR_NOT_FOUND)
717 {
718 AssertPtr(pKey);
719 if (pKey)
720 pKey->release();
721 return setError(VBOX_E_OBJECT_IN_USE, tr("A password with the given ID already exists"));
722 }
723 }
724
725 for (unsigned i = 0; i < aIdentifiers.size() && SUCCEEDED(hrc); i++)
726 {
727 size_t cbKey = aPasswords[i].length() + 1; /* Include terminator */
728 const uint8_t *pbKey = (const uint8_t *)aPasswords[i].c_str();
729
730 int rc = m->m_pSecretKeyStore->addSecretKey(aIdentifiers[i], pbKey, cbKey);
731 if (RT_SUCCESS(rc))
732 m->m_cPwProvided++;
733 else if (rc == VERR_NO_MEMORY)
734 hrc = setError(E_OUTOFMEMORY, tr("Failed to allocate enough secure memory for the key"));
735 else
736 hrc = setError(E_FAIL, tr("Unknown error happened while adding a password (%Rrc)"), rc);
737 }
738
739 return hrc;
740}
741
742////////////////////////////////////////////////////////////////////////////////
743//
744// Appliance private methods
745//
746////////////////////////////////////////////////////////////////////////////////
747
748HRESULT Appliance::i_initBackendNames()
749{
750 HRESULT hrc = S_OK;
751 if (!g_fInitializedBackendNames)
752 {
753 /*
754 * Use the system properties to translate file extensions into
755 * storage backend names.
756 */
757 static struct
758 {
759 const char *pszExt; /**< extension */
760 char *pszBackendName;
761 size_t cbBackendName;
762 } const s_aFormats[] =
763 {
764 { "iso", g_szIsoBackend, sizeof(g_szIsoBackend) },
765 { "vmdk", g_szVmdkBackend, sizeof(g_szVmdkBackend) },
766 { "vhd", g_szVhdBackend, sizeof(g_szVhdBackend) },
767 };
768 SystemProperties *pSysProps = mVirtualBox->i_getSystemProperties();
769 for (unsigned i = 0; i < RT_ELEMENTS(s_aFormats); i++)
770 {
771 ComObjPtr<MediumFormat> trgFormat = pSysProps->i_mediumFormatFromExtension(s_aFormats[i].pszExt);
772 if (trgFormat.isNotNull())
773 {
774 const char *pszName = trgFormat->i_getName().c_str();
775 int vrc = RTStrCopy(s_aFormats[i].pszBackendName, s_aFormats[i].cbBackendName, pszName);
776 AssertRCStmt(vrc, hrc = setError(E_FAIL, "Unexpected storage backend name copy error %Rrc for %s.", vrc, pszName));
777 }
778 else
779 hrc = setError(E_FAIL, tr("Can't find appropriate medium format for ISO type of a virtual disk."));
780 }
781
782 if (SUCCEEDED(hrc))
783 g_fInitializedBackendNames = true;
784 }
785
786 return hrc;
787}
788
789Utf8Str Appliance::i_typeOfVirtualDiskFormatFromURI(Utf8Str uri) const
790{
791 Assert(g_fInitializedBackendNames);
792
793 unsigned i = RT_ELEMENTS(g_aUriToBackend);
794 while (i-- > 0)
795 if (RTStrICmp(g_aUriToBackend[i].pszUri, uri.c_str()) == 0)
796 return Utf8Str(g_aUriToBackend[i].pszBackend);
797 return Utf8Str();
798}
799
800#if 0 /* unused */
801std::set<Utf8Str> Appliance::i_URIFromTypeOfVirtualDiskFormat(Utf8Str type)
802{
803 Assert(g_fInitializedBackendNames);
804
805 std::set<Utf8Str> UriSet;
806 unsigned i = RT_ELEMENTS(g_aUriToBackend);
807 while (i-- > 0)
808 if (RTStrICmp(g_aUriToBackend[i].pszBackend, type.c_str()) == 0)
809 UriSet.insert(g_aUriToBackend[i].pszUri);
810 return UriSet;
811}
812#endif
813
814/**
815 * Returns a medium format object corresponding to the given
816 * disk image or null if no such format.
817 *
818 * @param di Disk Image
819 * @param mf Medium Format
820 *
821 * @return ComObjPtr<MediumFormat>
822 */
823HRESULT Appliance::i_findMediumFormatFromDiskImage(const ovf::DiskImage &di, ComObjPtr<MediumFormat>& mf)
824{
825 HRESULT rc = S_OK;
826
827 /* Get the system properties. */
828 SystemProperties *pSysProps = mVirtualBox->i_getSystemProperties();
829
830 /* We need a proper source format description */
831 /* Which format to use? */
832 Utf8Str strSrcFormat = i_typeOfVirtualDiskFormatFromURI(di.strFormat);
833
834 /*
835 * fallback, if we can't determine virtual disk format using URI from the attribute ovf:format
836 * in the corresponding section <Disk> in the OVF file.
837 */
838 if (strSrcFormat.isEmpty())
839 {
840 strSrcFormat = di.strHref;
841
842 /* check either file gzipped or not
843 * if "yes" then remove last extension,
844 * i.e. "image.vmdk.gz"->"image.vmdk"
845 */
846 if (di.strCompression == "gzip")
847 {
848 if (RTPathHasSuffix(strSrcFormat.c_str()))
849 {
850 strSrcFormat.stripSuffix();
851 }
852 else
853 {
854 mf.setNull();
855 rc = setError(E_FAIL,
856 tr("Internal inconsistency looking up medium format for the disk image '%s'"),
857 di.strHref.c_str());
858 return rc;
859 }
860 }
861 /* Figure out from extension which format the image of disk has. */
862 if (RTPathHasSuffix(strSrcFormat.c_str()))
863 {
864 const char *pszExt = RTPathSuffix(strSrcFormat.c_str());
865 if (pszExt)
866 pszExt++;
867 mf = pSysProps->i_mediumFormatFromExtension(pszExt);
868 }
869 else
870 mf.setNull();
871 }
872 else
873 mf = pSysProps->i_mediumFormat(strSrcFormat);
874
875 if (mf.isNull())
876 rc = setError(E_FAIL, tr("Internal inconsistency looking up medium format for the disk image '%s'"),
877 di.strHref.c_str());
878
879 return rc;
880}
881
882/**
883 * Setup automatic I/O stream digest calculation, adding it to hOurManifest.
884 *
885 * @returns Passthru I/O stream, of @a hVfsIos if no digest calc needed.
886 * @param hVfsIos The stream to wrap. Always consumed.
887 * @param pszManifestEntry The manifest entry.
888 * @param fRead Set if read stream, clear if write.
889 * @throws Nothing.
890 */
891RTVFSIOSTREAM Appliance::i_manifestSetupDigestCalculationForGivenIoStream(RTVFSIOSTREAM hVfsIos, const char *pszManifestEntry,
892 bool fRead /*= true */)
893{
894 int vrc;
895 Assert(!RTManifestPtIosIsInstanceOf(hVfsIos));
896
897 if (m->fDigestTypes == 0)
898 return hVfsIos;
899
900 /* Create the manifest if necessary. */
901 if (m->hOurManifest == NIL_RTMANIFEST)
902 {
903 vrc = RTManifestCreate(0 /*fFlags*/, &m->hOurManifest);
904 AssertRCReturnStmt(vrc, RTVfsIoStrmRelease(hVfsIos), NIL_RTVFSIOSTREAM);
905 }
906
907 /* Setup the stream. */
908 RTVFSIOSTREAM hVfsIosPt;
909 vrc = RTManifestEntryAddPassthruIoStream(m->hOurManifest, hVfsIos, pszManifestEntry, m->fDigestTypes, fRead, &hVfsIosPt);
910
911 RTVfsIoStrmRelease(hVfsIos); /* always consumed! */
912 if (RT_SUCCESS(vrc))
913 return hVfsIosPt;
914
915 setErrorVrc(vrc, "RTManifestEntryAddPassthruIoStream failed with rc=%Rrc", vrc);
916 return NIL_RTVFSIOSTREAM;
917}
918
919/**
920 * Returns true if the appliance is in "idle" state. This should always be the
921 * case unless an import or export is currently in progress. Similar to machine
922 * states, this permits the Appliance implementation code to let go of the
923 * Appliance object lock while a time-consuming disk conversion is in progress
924 * without exposing the appliance to conflicting calls.
925 *
926 * This sets an error on "this" (the appliance) and returns false if the appliance
927 * is busy. The caller should then return E_ACCESSDENIED.
928 *
929 * Must be called from under the object lock!
930 */
931bool Appliance::i_isApplianceIdle()
932{
933 if (m->state == ApplianceImporting)
934 setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy importing files"));
935 else if (m->state == ApplianceExporting)
936 setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy exporting files"));
937 else
938 return true;
939
940 return false;
941}
942
943HRESULT Appliance::i_searchUniqueVMName(Utf8Str& aName) const
944{
945 IMachine *machine = NULL;
946 char *tmpName = RTStrDup(aName.c_str());
947 int i = 1;
948 while (mVirtualBox->FindMachine(Bstr(tmpName).raw(), &machine) != VBOX_E_OBJECT_NOT_FOUND)
949 {
950 RTStrFree(tmpName);
951 RTStrAPrintf(&tmpName, "%s %d", aName.c_str(), i);
952 ++i;
953 }
954 aName = tmpName;
955 RTStrFree(tmpName);
956
957 return S_OK;
958}
959
960HRESULT Appliance::i_searchUniqueImageFilePath(const Utf8Str &aMachineFolder, DeviceType_T aDeviceType, Utf8Str &aName) const
961{
962 /*
963 * Check if the file exists or if a medium with this path is registered already
964 */
965 Utf8Str strAbsName;
966 ssize_t offDashNum = -1;
967 ssize_t cchDashNum = 0;
968 for (unsigned i = 1;; i++)
969 {
970 /* Complete the path (could be relative to machine folder). */
971 int rc = RTPathAbsExCxx(strAbsName, aMachineFolder, aName);
972 AssertRCReturn(rc, Global::vboxStatusCodeToCOM(rc)); /** @todo stupid caller ignores this */
973
974 /* Check that the file does not exist and that there is no media somehow matching the name. */
975 if (!RTPathExists(strAbsName.c_str()))
976 {
977 ComPtr<IMedium> ptrMedium;
978 HRESULT hrc = mVirtualBox->OpenMedium(Bstr(strAbsName).raw(), aDeviceType, AccessMode_ReadWrite,
979 FALSE /* fForceNewUuid */, ptrMedium.asOutParam());
980 if (hrc == VBOX_E_OBJECT_NOT_FOUND)
981 return S_OK;
982 }
983
984 /* Insert '_%i' before the suffix and try again. */
985 if (offDashNum < 0)
986 {
987 const char *pszSuffix = RTPathSuffix(aName.c_str());
988 offDashNum = pszSuffix ? pszSuffix - aName.c_str() : aName.length();
989 }
990 char szTmp[32];
991 size_t cchTmp = RTStrPrintf(szTmp, sizeof(szTmp), "_%u", i);
992 aName.replace(offDashNum, cchDashNum, szTmp, cchTmp);
993 cchDashNum = cchTmp;
994 }
995}
996
997/**
998 * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a
999 * progress object with the proper weights and maximum progress values.
1000 */
1001HRESULT Appliance::i_setUpProgress(ComObjPtr<Progress> &pProgress,
1002 const Utf8Str &strDescription,
1003 SetUpProgressMode mode)
1004{
1005 HRESULT rc;
1006
1007 /* Create the progress object */
1008 try
1009 {
1010 rc = pProgress.createObject();
1011 if (FAILED(rc))
1012 return rc;
1013 }
1014 catch (std::bad_alloc &)
1015 {
1016 return E_OUTOFMEMORY;
1017 }
1018
1019 // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data)
1020 i_disksWeight();
1021
1022 m->ulWeightForManifestOperation = 0;
1023
1024 ULONG cOperations = 1 // one for XML setup
1025 + m->cDisks; // plus one per disk
1026 ULONG ulTotalOperationsWeight;
1027 if (m->ulTotalDisksMB)
1028 {
1029 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML
1030 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
1031 }
1032 else
1033 {
1034 // no disks to export:
1035 m->ulWeightForXmlOperation = 1;
1036 ulTotalOperationsWeight = 1;
1037 }
1038
1039 switch (mode)
1040 {
1041 case ImportFile:
1042 {
1043 break;
1044 }
1045 case WriteFile:
1046 {
1047 // assume that creating the manifest will take .1% of the time it takes to export the disks
1048 if (m->fManifest)
1049 {
1050 ++cOperations; // another one for creating the manifest
1051
1052 m->ulWeightForManifestOperation = (ULONG)((double)m->ulTotalDisksMB * .1 / 100); // use .5% of the
1053 // progress for the manifest
1054 ulTotalOperationsWeight += m->ulWeightForManifestOperation;
1055 }
1056 break;
1057 }
1058 case ImportS3:
1059 {
1060 cOperations += 1 + 1; // another one for the manifest file & another one for the import
1061 ulTotalOperationsWeight = m->ulTotalDisksMB;
1062 if (!m->ulTotalDisksMB)
1063 // no disks to export:
1064 ulTotalOperationsWeight = 1;
1065
1066 ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import
1067 ulTotalOperationsWeight += ulImportWeight;
1068
1069 m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */
1070
1071 ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init
1072 ulTotalOperationsWeight += ulInitWeight;
1073 break;
1074 }
1075 case WriteS3:
1076 {
1077 cOperations += 1 + 1; // another one for the mf & another one for temporary creation
1078
1079 if (m->ulTotalDisksMB)
1080 {
1081 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress
1082 // for OVF file upload
1083 // (we didn't know the
1084 // size at this point)
1085 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
1086 }
1087 else
1088 {
1089 // no disks to export:
1090 ulTotalOperationsWeight = 1;
1091 m->ulWeightForXmlOperation = 1;
1092 }
1093 ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the
1094 creation of the OVF
1095 & the disks */
1096 ulTotalOperationsWeight += ulOVFCreationWeight;
1097 break;
1098 }
1099 case ExportCloud:
1100 case ImportCloud:
1101 break;
1102 }
1103 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n",
1104 m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation));
1105
1106 return pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
1107 strDescription,
1108 TRUE /* aCancelable */,
1109 cOperations, // ULONG cOperations,
1110 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
1111 strDescription, // CBSTR bstrFirstOperationDescription,
1112 m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight,
1113}
1114
1115void Appliance::i_addWarning(const char* aWarning, ...)
1116{
1117 try
1118 {
1119 va_list args;
1120 va_start(args, aWarning);
1121 Utf8Str str(aWarning, args);
1122 va_end(args);
1123 m->llWarnings.push_back(str);
1124 }
1125 catch (...)
1126 {
1127 AssertFailed();
1128 }
1129}
1130
1131/**
1132 * Refreshes the cDisks and ulTotalDisksMB members in the instance data.
1133 * Requires that virtual system descriptions are present.
1134 */
1135void Appliance::i_disksWeight()
1136{
1137 m->ulTotalDisksMB = 0;
1138 m->cDisks = 0;
1139 // weigh the disk images according to their sizes
1140 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
1141 for (it = m->virtualSystemDescriptions.begin();
1142 it != m->virtualSystemDescriptions.end();
1143 ++it)
1144 {
1145 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
1146 /* One for every medium of the Virtual System */
1147 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->i_findByType(VirtualSystemDescriptionType_HardDiskImage);
1148 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
1149 for (itH = avsdeHDs.begin();
1150 itH != avsdeHDs.end();
1151 ++itH)
1152 {
1153 const VirtualSystemDescriptionEntry *pHD = *itH;
1154 m->ulTotalDisksMB += pHD->ulSizeMB;
1155 ++m->cDisks;
1156 }
1157
1158 avsdeHDs = vsdescThis->i_findByType(VirtualSystemDescriptionType_CDROM);
1159 for (itH = avsdeHDs.begin();
1160 itH != avsdeHDs.end();
1161 ++itH)
1162 {
1163 const VirtualSystemDescriptionEntry *pHD = *itH;
1164 m->ulTotalDisksMB += pHD->ulSizeMB;
1165 ++m->cDisks;
1166 }
1167 }
1168
1169}
1170
1171void Appliance::i_parseBucket(Utf8Str &aPath, Utf8Str &aBucket)
1172{
1173 /* Buckets are S3 specific. So parse the bucket out of the file path */
1174 if (!aPath.startsWith("/"))
1175 throw setError(E_INVALIDARG,
1176 tr("The path '%s' must start with /"), aPath.c_str());
1177 size_t bpos = aPath.find("/", 1);
1178 if (bpos != Utf8Str::npos)
1179 {
1180 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
1181 aPath = aPath.substr(bpos); /* The rest of the file path */
1182 }
1183 /* If there is no bucket name provided reject it */
1184 if (aBucket.isEmpty())
1185 throw setError(E_INVALIDARG,
1186 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
1187}
1188
1189/**
1190 * Worker for TaskOVF::handler.
1191 *
1192 * The TaskOVF is started in Appliance::readImpl() and Appliance::importImpl()
1193 * and Appliance::writeImpl().
1194 *
1195 * This will in turn call Appliance::readFS() or Appliance::importFS() or
1196 * Appliance::writeFS().
1197 *
1198 * @thread pTask The task.
1199 */
1200/* static */ void Appliance::i_importOrExportThreadTask(TaskOVF *pTask)
1201{
1202 LogFlowFuncEnter();
1203 AssertReturnVoid(pTask);
1204
1205 Appliance *pAppliance = pTask->pAppliance;
1206 LogFlowFunc(("Appliance %p taskType=%d\n", pAppliance, pTask->taskType));
1207
1208 switch (pTask->taskType)
1209 {
1210 case TaskOVF::Read:
1211 pAppliance->m->resetReadData();
1212 if (pTask->locInfo.storageType == VFSType_File)
1213 pTask->rc = pAppliance->i_readFS(pTask);
1214 else
1215 pTask->rc = E_NOTIMPL;
1216 break;
1217
1218 case TaskOVF::Import:
1219 /** @todo allow overriding these? */
1220 if (!pAppliance->m->fSignatureValid && pAppliance->m->pbSignedDigest)
1221 pTask->rc = pAppliance->setError(E_FAIL, tr("The manifest signature for '%s' is not valid"),
1222 pTask->locInfo.strPath.c_str());
1223 else if (!pAppliance->m->fCertificateValid && pAppliance->m->pbSignedDigest)
1224 {
1225 if (pAppliance->m->strCertError.isNotEmpty())
1226 pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is not valid: %s"),
1227 pTask->locInfo.strPath.c_str(), pAppliance->m->strCertError.c_str());
1228 else
1229 pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is not valid"),
1230 pTask->locInfo.strPath.c_str());
1231 }
1232 // fusion does not consider this a show stopper (we've filed a warning during read).
1233 //else if (pAppliance->m->fCertificateMissingPath && pAppliance->m->pbSignedDigest)
1234 // pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is does not have a valid CA path"),
1235 // pTask->locInfo.strPath.c_str());
1236 else
1237 {
1238 if (pTask->locInfo.storageType == VFSType_File)
1239 pTask->rc = pAppliance->i_importFS(pTask);
1240 else
1241 pTask->rc = E_NOTIMPL;
1242 }
1243 break;
1244
1245 case TaskOVF::Write:
1246 if (pTask->locInfo.storageType == VFSType_File)
1247 pTask->rc = pAppliance->i_writeFS(pTask);
1248 else
1249 pTask->rc = E_NOTIMPL;
1250 break;
1251
1252 default:
1253 AssertFailed();
1254 pTask->rc = E_FAIL;
1255 break;
1256 }
1257
1258 if (!pTask->pProgress.isNull())
1259 pTask->pProgress->i_notifyComplete(pTask->rc);
1260
1261 LogFlowFuncLeave();
1262}
1263
1264/* static */ DECLCALLBACK(int) Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
1265{
1266 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
1267
1268 if ( pTask
1269 && !pTask->pProgress.isNull())
1270 {
1271 BOOL fCanceled;
1272 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
1273 if (fCanceled)
1274 return -1;
1275 pTask->pProgress->SetCurrentOperationProgress(uPercent);
1276 }
1277 return VINF_SUCCESS;
1278}
1279
1280/**
1281 * Worker for TaskOPC::handler.
1282 * @thread pTask The task.
1283 */
1284/* static */
1285void Appliance::i_exportOPCThreadTask(TaskOPC *pTask)
1286{
1287 LogFlowFuncEnter();
1288 AssertReturnVoid(pTask);
1289
1290 Appliance *pAppliance = pTask->pAppliance;
1291 LogFlowFunc(("Appliance %p taskType=%d\n", pAppliance, pTask->taskType));
1292
1293 switch (pTask->taskType)
1294 {
1295 case TaskOPC::Export:
1296 pTask->rc = pAppliance->i_writeFSOPC(pTask);
1297 break;
1298
1299 default:
1300 AssertFailed();
1301 pTask->rc = E_FAIL;
1302 break;
1303 }
1304
1305 if (!pTask->pProgress.isNull())
1306 pTask->pProgress->i_notifyComplete(pTask->rc);
1307
1308 LogFlowFuncLeave();
1309}
1310
1311/* static */
1312DECLCALLBACK(int) Appliance::TaskOPC::updateProgress(unsigned uPercent, void *pvUser)
1313{
1314 Appliance::TaskOPC* pTask = *(Appliance::TaskOPC**)pvUser;
1315
1316 if ( pTask
1317 && !pTask->pProgress.isNull())
1318 {
1319 BOOL fCanceled;
1320 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
1321 if (fCanceled)
1322 return -1;
1323 pTask->pProgress->SetCurrentOperationProgress(uPercent);
1324 }
1325 return VINF_SUCCESS;
1326}
1327
1328/**
1329 * Worker for TaskCloud::handler.
1330 * @thread pTask The task.
1331 */
1332/* static */
1333void Appliance::i_importOrExportCloudThreadTask(TaskCloud *pTask)
1334{
1335 LogFlowFuncEnter();
1336 AssertReturnVoid(pTask);
1337
1338 Appliance *pAppliance = pTask->pAppliance;
1339 LogFlowFunc(("Appliance %p taskType=%d\n", pAppliance, pTask->taskType));
1340
1341 switch (pTask->taskType)
1342 {
1343 case TaskCloud::Export:
1344 pAppliance->i_setApplianceState(ApplianceExporting);
1345 pTask->rc = pAppliance->i_exportCloudImpl(pTask);
1346 break;
1347 case TaskCloud::Import:
1348 pAppliance->i_setApplianceState(ApplianceImporting);
1349 pTask->rc = pAppliance->i_importCloudImpl(pTask);
1350 break;
1351 case TaskCloud::ReadData:
1352 pAppliance->i_setApplianceState(ApplianceImporting);
1353 pTask->rc = pAppliance->i_gettingCloudData(pTask);
1354 break;
1355 default:
1356 AssertFailed();
1357 pTask->rc = E_FAIL;
1358 break;
1359 }
1360
1361 pAppliance->i_setApplianceState(ApplianceIdle);
1362
1363 if (!pTask->pProgress.isNull())
1364 pTask->pProgress->i_notifyComplete(pTask->rc);
1365
1366 LogFlowFuncLeave();
1367}
1368
1369/* static */
1370DECLCALLBACK(int) Appliance::TaskCloud::updateProgress(unsigned uPercent, void *pvUser)
1371{
1372 Appliance::TaskCloud* pTask = *(Appliance::TaskCloud**)pvUser;
1373
1374 if ( pTask
1375 && !pTask->pProgress.isNull())
1376 {
1377 BOOL fCanceled;
1378 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
1379 if (fCanceled)
1380 return -1;
1381 pTask->pProgress->SetCurrentOperationProgress(uPercent);
1382 }
1383 return VINF_SUCCESS;
1384}
1385
1386void i_parseURI(Utf8Str strUri, LocationInfo &locInfo)
1387{
1388 /* Check the URI for the protocol */
1389 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
1390 {
1391 locInfo.storageType = VFSType_File;
1392 strUri = strUri.substr(sizeof("file://") - 1);
1393 }
1394 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
1395 {
1396 locInfo.storageType = VFSType_S3;
1397 strUri = strUri.substr(sizeof("SunCloud://") - 1);
1398 }
1399 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
1400 {
1401 locInfo.storageType = VFSType_S3;
1402 strUri = strUri.substr(sizeof("S3://") - 1);
1403 }
1404 else if (strUri.startsWith("OCI://", Utf8Str::CaseInsensitive)) /* OCI service (storage or compute) */
1405 {
1406 locInfo.storageType = VFSType_Cloud;
1407 locInfo.strProvider = "OCI";
1408 strUri = strUri.substr(sizeof("OCI://") - 1);
1409 }
1410 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
1411 throw E_NOTIMPL;
1412
1413 /* Not necessary on a file based URI */
1414// if (locInfo.storageType != VFSType_File)
1415// {
1416// size_t uppos = strUri.find("@"); /* username:password combo */
1417// if (uppos != Utf8Str::npos)
1418// {
1419// locInfo.strUsername = strUri.substr(0, uppos);
1420// strUri = strUri.substr(uppos + 1);
1421// size_t upos = locInfo.strUsername.find(":");
1422// if (upos != Utf8Str::npos)
1423// {
1424// locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
1425// locInfo.strUsername = locInfo.strUsername.substr(0, upos);
1426// }
1427// }
1428// size_t hpos = strUri.find("/"); /* hostname part */
1429// if (hpos != Utf8Str::npos)
1430// {
1431// locInfo.strHostname = strUri.substr(0, hpos);
1432// strUri = strUri.substr(hpos);
1433// }
1434// }
1435
1436 locInfo.strPath = strUri;
1437}
1438
1439
1440////////////////////////////////////////////////////////////////////////////////
1441//
1442// IVirtualSystemDescription constructor / destructor
1443//
1444////////////////////////////////////////////////////////////////////////////////
1445
1446/**
1447 * COM initializer.
1448 * @return
1449 */
1450HRESULT VirtualSystemDescription::init()
1451{
1452 /* Enclose the state transition NotReady->InInit->Ready */
1453 AutoInitSpan autoInitSpan(this);
1454 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1455
1456 /* Initialize data */
1457 m = new Data();
1458 m->pConfig = NULL;
1459
1460 /* Confirm a successful initialization */
1461 autoInitSpan.setSucceeded();
1462 return S_OK;
1463}
1464
1465/**
1466* COM uninitializer.
1467*/
1468
1469void VirtualSystemDescription::uninit()
1470{
1471 if (m->pConfig)
1472 delete m->pConfig;
1473 delete m;
1474 m = NULL;
1475}
1476
1477
1478////////////////////////////////////////////////////////////////////////////////
1479//
1480// IVirtualSystemDescription public methods
1481//
1482////////////////////////////////////////////////////////////////////////////////
1483
1484/**
1485 * Public method implementation.
1486 */
1487HRESULT VirtualSystemDescription::getCount(ULONG *aCount)
1488{
1489 if (!aCount)
1490 return E_POINTER;
1491
1492 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1493
1494 *aCount = (ULONG)m->maDescriptions.size();
1495 return S_OK;
1496}
1497
1498/**
1499 * Public method implementation.
1500 */
1501HRESULT VirtualSystemDescription::getDescription(std::vector<VirtualSystemDescriptionType_T> &aTypes,
1502 std::vector<com::Utf8Str> &aRefs,
1503 std::vector<com::Utf8Str> &aOVFValues,
1504 std::vector<com::Utf8Str> &aVBoxValues,
1505 std::vector<com::Utf8Str> &aExtraConfigValues)
1506
1507{
1508 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1509 size_t c = m->maDescriptions.size();
1510 aTypes.resize(c);
1511 aRefs.resize(c);
1512 aOVFValues.resize(c);
1513 aVBoxValues.resize(c);
1514 aExtraConfigValues.resize(c);
1515
1516 for (size_t i = 0; i < c; i++)
1517 {
1518 const VirtualSystemDescriptionEntry &vsde = m->maDescriptions[i];
1519 aTypes[i] = vsde.type;
1520 aRefs[i] = vsde.strRef;
1521 aOVFValues[i] = vsde.strOvf;
1522 aVBoxValues[i] = vsde.strVBoxCurrent;
1523 aExtraConfigValues[i] = vsde.strExtraConfigCurrent;
1524 }
1525 return S_OK;
1526}
1527
1528/**
1529 * Public method implementation.
1530 */
1531HRESULT VirtualSystemDescription::getDescriptionByType(VirtualSystemDescriptionType_T aType,
1532 std::vector<VirtualSystemDescriptionType_T> &aTypes,
1533 std::vector<com::Utf8Str> &aRefs,
1534 std::vector<com::Utf8Str> &aOVFValues,
1535 std::vector<com::Utf8Str> &aVBoxValues,
1536 std::vector<com::Utf8Str> &aExtraConfigValues)
1537{
1538 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1539 std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType(aType);
1540
1541 size_t c = vsd.size();
1542 aTypes.resize(c);
1543 aRefs.resize(c);
1544 aOVFValues.resize(c);
1545 aVBoxValues.resize(c);
1546 aExtraConfigValues.resize(c);
1547
1548 size_t i = 0;
1549 for (list<VirtualSystemDescriptionEntry*>::const_iterator it = vsd.begin(); it != vsd.end(); ++it, ++i)
1550 {
1551 const VirtualSystemDescriptionEntry *vsde = (*it);
1552 aTypes[i] = vsde->type;
1553 aRefs[i] = vsde->strRef;
1554 aOVFValues[i] = vsde->strOvf;
1555 aVBoxValues[i] = vsde->strVBoxCurrent;
1556 aExtraConfigValues[i] = vsde->strExtraConfigCurrent;
1557 }
1558
1559 return S_OK;
1560}
1561
1562/**
1563 * Public method implementation.
1564 */
1565HRESULT VirtualSystemDescription::getValuesByType(VirtualSystemDescriptionType_T aType,
1566 VirtualSystemDescriptionValueType_T aWhich,
1567 std::vector<com::Utf8Str> &aValues)
1568{
1569 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1570
1571 std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType (aType);
1572 aValues.resize((ULONG)vsd.size());
1573
1574 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1575 size_t i = 0;
1576 for (it = vsd.begin();
1577 it != vsd.end();
1578 ++it, ++i)
1579 {
1580 const VirtualSystemDescriptionEntry *vsde = (*it);
1581
1582 Bstr bstr;
1583 switch (aWhich)
1584 {
1585 case VirtualSystemDescriptionValueType_Reference: aValues[i] = vsde->strRef; break;
1586 case VirtualSystemDescriptionValueType_Original: aValues[i] = vsde->strOvf; break;
1587 case VirtualSystemDescriptionValueType_Auto: aValues[i] = vsde->strVBoxCurrent; break;
1588 case VirtualSystemDescriptionValueType_ExtraConfig: aValues[i] = vsde->strExtraConfigCurrent; break;
1589#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
1590 case VirtualSystemDescriptionValueType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
1591#endif
1592 }
1593 }
1594
1595 return S_OK;
1596}
1597
1598/**
1599 * Public method implementation.
1600 */
1601HRESULT VirtualSystemDescription::setFinalValues(const std::vector<BOOL> &aEnabled,
1602 const std::vector<com::Utf8Str> &aVBoxValues,
1603 const std::vector<com::Utf8Str> &aExtraConfigValues)
1604{
1605#ifndef RT_OS_WINDOWS
1606 // NOREF(aEnabledSize);
1607#endif /* RT_OS_WINDOWS */
1608 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1609
1610 if ( (aEnabled.size() != m->maDescriptions.size())
1611 || (aVBoxValues.size() != m->maDescriptions.size())
1612 || (aExtraConfigValues.size() != m->maDescriptions.size())
1613 )
1614 return E_INVALIDARG;
1615
1616 size_t i = 0;
1617 for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1618 it != m->maDescriptions.end();
1619 ++it, ++i)
1620 {
1621 VirtualSystemDescriptionEntry& vsde = *it;
1622
1623 if (aEnabled[i])
1624 {
1625 vsde.strVBoxCurrent = aVBoxValues[i];
1626 vsde.strExtraConfigCurrent = aExtraConfigValues[i];
1627 }
1628 else
1629 vsde.type = VirtualSystemDescriptionType_Ignore;
1630 }
1631
1632 return S_OK;
1633}
1634
1635/**
1636 * Public method implementation.
1637 */
1638HRESULT VirtualSystemDescription::addDescription(VirtualSystemDescriptionType_T aType,
1639 const com::Utf8Str &aVBoxValue,
1640 const com::Utf8Str &aExtraConfigValue)
1641
1642{
1643 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1644 i_addEntry(aType, "", aVBoxValue, aVBoxValue, 0, aExtraConfigValue);
1645 return S_OK;
1646}
1647
1648/**
1649 * Internal method; adds a new description item to the member list.
1650 * @param aType Type of description for the new item.
1651 * @param strRef Reference item; only used with storage controllers.
1652 * @param aOvfValue Corresponding original value from OVF.
1653 * @param aVBoxValue Initial configuration value (can be overridden by caller with setFinalValues).
1654 * @param ulSizeMB Weight for IProgress
1655 * @param strExtraConfig Extra configuration; meaning dependent on type.
1656 */
1657void VirtualSystemDescription::i_addEntry(VirtualSystemDescriptionType_T aType,
1658 const Utf8Str &strRef,
1659 const Utf8Str &aOvfValue,
1660 const Utf8Str &aVBoxValue,
1661 uint32_t ulSizeMB,
1662 const Utf8Str &strExtraConfig /*= ""*/)
1663{
1664 VirtualSystemDescriptionEntry vsde;
1665 vsde.ulIndex = (uint32_t)m->maDescriptions.size(); // each entry gets an index so the client side can reference them
1666 vsde.type = aType;
1667 vsde.strRef = strRef;
1668 vsde.strOvf = aOvfValue;
1669 vsde.strVBoxSuggested /* remember original value */
1670 = vsde.strVBoxCurrent /* and set current value which can be overridden by setFinalValues() */
1671 = aVBoxValue;
1672 vsde.strExtraConfigSuggested
1673 = vsde.strExtraConfigCurrent
1674 = strExtraConfig;
1675 vsde.ulSizeMB = ulSizeMB;
1676
1677 vsde.skipIt = false;
1678
1679 m->maDescriptions.push_back(vsde);
1680}
1681
1682/**
1683 * Private method; returns a list of description items containing all the items from the member
1684 * description items of this virtual system that match the given type.
1685 */
1686std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::i_findByType(VirtualSystemDescriptionType_T aType)
1687{
1688 std::list<VirtualSystemDescriptionEntry*> vsd;
1689 for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1690 it != m->maDescriptions.end();
1691 ++it)
1692 {
1693 if (it->type == aType)
1694 vsd.push_back(&(*it));
1695 }
1696
1697 return vsd;
1698}
1699
1700HRESULT VirtualSystemDescription::removeDescriptionByType(VirtualSystemDescriptionType_T aType)
1701{
1702 std::vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1703 while (it != m->maDescriptions.end())
1704 {
1705 if (it->type == aType)
1706 it = m->maDescriptions.erase(it);
1707 else
1708 ++it;
1709 }
1710
1711 return S_OK;
1712}
1713
1714/* Private method; delete all records from the list
1715 * m->llDescriptions that match the given type.
1716 */
1717void VirtualSystemDescription::i_removeByType(VirtualSystemDescriptionType_T aType)
1718{
1719 std::vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1720 while (it != m->maDescriptions.end())
1721 {
1722 if (it->type == aType)
1723 it = m->maDescriptions.erase(it);
1724 else
1725 ++it;
1726 }
1727}
1728
1729/**
1730 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1731 * the given reference ID. Useful when needing the controller for a particular
1732 * virtual disk.
1733 */
1734const VirtualSystemDescriptionEntry* VirtualSystemDescription::i_findControllerFromID(uint32_t id)
1735{
1736 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1737 vector<VirtualSystemDescriptionEntry>::const_iterator it;
1738 for (it = m->maDescriptions.begin();
1739 it != m->maDescriptions.end();
1740 ++it)
1741 {
1742 const VirtualSystemDescriptionEntry &d = *it;
1743 switch (d.type)
1744 {
1745 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1746 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1747 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1748 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1749 if (d.strRef == strRef)
1750 return &d;
1751 break;
1752 default: break; /* Shut up MSC. */
1753 }
1754 }
1755
1756 return NULL;
1757}
1758
1759/**
1760 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1761 * contains a <vbox:Machine> element. This method then attempts to parse that and
1762 * create a MachineConfigFile instance from it which is stored in this instance data
1763 * and can then be used to create a machine.
1764 *
1765 * This must only be called once per instance.
1766 *
1767 * This rethrows all XML and logic errors from MachineConfigFile.
1768 *
1769 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1770 * DOM tree.
1771 */
1772void VirtualSystemDescription::i_importVBoxMachineXML(const xml::ElementNode &elmMachine)
1773{
1774 settings::MachineConfigFile *pConfig = NULL;
1775
1776 Assert(m->pConfig == NULL);
1777
1778 try
1779 {
1780 pConfig = new settings::MachineConfigFile(NULL);
1781 pConfig->importMachineXML(elmMachine);
1782
1783 m->pConfig = pConfig;
1784 }
1785 catch (...)
1786 {
1787 if (pConfig)
1788 delete pConfig;
1789 throw;
1790 }
1791}
1792
1793/**
1794 * Returns the machine config created by importVBoxMachineXML() or NULL if there's none.
1795 */
1796const settings::MachineConfigFile* VirtualSystemDescription::i_getMachineConfig() const
1797{
1798 return m->pConfig;
1799}
1800
Note: See TracBrowser for help on using the repository browser.

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