VirtualBox

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

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

bugref:9781. Added the placeholder @@VBOX_COND_GUEST_VERSION[>(required version)]@@. Updated the templates. Removed the obsolete function getGuestOSConditional().

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