VirtualBox

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

Last change on this file since 95140 was 94478, checked in by vboxsync, 3 years ago

VBox/ostypes.h+Main/Global,Appliance+FE/Qt: Some Solaris OStype cleanup:
the Solaris 10 10/09 OStype was accidentally entwined with OpenSolaris in
the Global::sOSTypes[] table so separate them into a Solaris 10U8
(10/09) OS type and an OpenSolaris/Illumos/OpenIndiana OS type. Also
update the GUI icon and regex matching for these and other Solaris
versions.

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

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