VirtualBox

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

Last change on this file since 100827 was 100827, checked in by vboxsync, 10 months ago

VBox/ostypes.h+Main/{Global,Appliance},VMMDev,FE/Qt: Update the Linux OS
subtypes with recent releases: Debian 12 and Ubuntu 22.10 and 23.04.
bugref:5936

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

© 2023 Oracle
ContactPrivacy policyTerms of Use