VirtualBox

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

Last change on this file since 107212 was 107121, checked in by vboxsync, 3 months ago

VBox/ostypes.h+Main/{Global,Appliance}+VMMDev+FE/Qt: Add two new OStypes
for Windows 10 and 11 on ARM. bugref:10732

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