VirtualBox

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

Last change on this file since 94090 was 93480, checked in by vboxsync, 3 years ago

Main/Appliance: Allow users to specify a different storage controller
and/or controller port for hard disks when importing a VM. bugref:5027

'VBoxManage import foo.ova -n' has always presented a --controller
option for hard disks but the code to implement this had never been
implemented. This changeset adds the --controller functionality and
also includes a --port option for changing the controller port as well.

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