VirtualBox

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

Last change on this file since 98351 was 98289, checked in by vboxsync, 23 months ago

Main/src-server: rc -> hrc/vrc (partial). bugref:10223

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