VirtualBox

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

Last change on this file since 86697 was 86650, checked in by vboxsync, 4 years ago

Fixed bad commit. Hope this help.

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