VirtualBox

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

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

Main/Appliance: There should be no need to store two copies of the manifest. Also, we must not return unsanitized strings thru the API. IFF there is genuine need for non-sanitized data, we must return it as a BYTE array rather than a unicode string. bugref:9699

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

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