VirtualBox

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

Last change on this file since 73768 was 73743, checked in by vboxsync, 6 years ago

Main/Progress+Appliance+Machine: Turn IProgress::waitForAsyncProgressCompletion into an internal method. It is not needed by any client code outside the API, it's simply is too special. Also include the error propagation which it originally skipped (leding to reduntant code in the calling code). Remove a replicated version of it from the Appliance code which seems to be the half-forgotten ancestor of the method in IProgress. Adapt the users of the method to the new internal method, which made the code easier to read.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use