VirtualBox

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

Last change on this file since 106402 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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