VirtualBox

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

Last change on this file since 90441 was 90424, checked in by vboxsync, 3 years ago

Main/Appliance: Allow arbitrary unique resource IDs, not just integers. The OVF spec examples and the vast majority of OVF files use purely integers (and appliance export in VirtualBox also uses integers), but the type declaration allows any string.

  • 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 90424 2021-07-30 12:41:38Z 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(const Utf8Str &id)
1760{
1761 vector<VirtualSystemDescriptionEntry>::const_iterator it;
1762 for (it = m->maDescriptions.begin();
1763 it != m->maDescriptions.end();
1764 ++it)
1765 {
1766 const VirtualSystemDescriptionEntry &d = *it;
1767 switch (d.type)
1768 {
1769 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1770 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1771 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1772 case VirtualSystemDescriptionType_HardDiskControllerVirtioSCSI:
1773 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1774 if (d.strRef == id)
1775 return &d;
1776 break;
1777 default: break; /* Shut up MSC. */
1778 }
1779 }
1780
1781 return NULL;
1782}
1783
1784/**
1785 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1786 * contains a <vbox:Machine> element. This method then attempts to parse that and
1787 * create a MachineConfigFile instance from it which is stored in this instance data
1788 * and can then be used to create a machine.
1789 *
1790 * This must only be called once per instance.
1791 *
1792 * This rethrows all XML and logic errors from MachineConfigFile.
1793 *
1794 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1795 * DOM tree.
1796 */
1797void VirtualSystemDescription::i_importVBoxMachineXML(const xml::ElementNode &elmMachine)
1798{
1799 settings::MachineConfigFile *pConfig = NULL;
1800
1801 Assert(m->pConfig == NULL);
1802
1803 try
1804 {
1805 pConfig = new settings::MachineConfigFile(NULL);
1806 pConfig->importMachineXML(elmMachine);
1807
1808 m->pConfig = pConfig;
1809 }
1810 catch (...)
1811 {
1812 if (pConfig)
1813 delete pConfig;
1814 throw;
1815 }
1816}
1817
1818/**
1819 * Returns the machine config created by importVBoxMachineXML() or NULL if there's none.
1820 */
1821const settings::MachineConfigFile* VirtualSystemDescription::i_getMachineConfig() const
1822{
1823 return m->pConfig;
1824}
1825
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