VirtualBox

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

Last change on this file since 77039 was 76592, checked in by vboxsync, 6 years ago

Main: Don't use Logging.h.

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