VirtualBox

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

Last change on this file since 73003 was 72973, checked in by vboxsync, 6 years ago

Main: Some early sketches on how to get proper C++ enums with xpidl.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 60.3 KB
Line 
1/* $Id: ApplianceImpl.cpp 72973 2018-07-08 13:23:58Z 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 /** @todo Maybe too cost-intensive; try to find a lighter way */
899 while (mVirtualBox->FindMachine(Bstr(tmpName).raw(), &machine) != VBOX_E_OBJECT_NOT_FOUND)
900 {
901 RTStrFree(tmpName);
902 RTStrAPrintf(&tmpName, "%s %d", aName.c_str(), i);
903 ++i;
904 }
905 aName = tmpName;
906 RTStrFree(tmpName);
907
908 return S_OK;
909}
910
911HRESULT Appliance::i_searchUniqueDiskImageFilePath(const Utf8Str &aMachineFolder, Utf8Str &aName) const
912{
913 IMedium *harddisk = NULL;
914 char *tmpName = RTStrDup(aName.c_str());
915 char *tmpAbsName = RTPathAbsExDup(aMachineFolder.c_str(), tmpName);
916 int i = 1;
917 /* Check if the file exists or if a file with this path is registered
918 * already */
919 /** @todo Maybe too cost-intensive; try to find a lighter way */
920 while ( RTPathExists(tmpAbsName)
921 || mVirtualBox->OpenMedium(Bstr(tmpAbsName).raw(), DeviceType_HardDisk, AccessMode_ReadWrite,
922 FALSE /* fForceNewUuid */, &harddisk) != VBOX_E_OBJECT_NOT_FOUND)
923 {
924 RTStrFree(tmpAbsName);
925 char *tmpDir = RTStrDup(aName.c_str());
926 RTPathStripFilename(tmpDir);
927 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
928 RTPathStripSuffix(tmpFile);
929 const char *pszTmpSuff = RTPathSuffix(aName.c_str());
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
1051/**
1052 * Called from the import and export background threads to synchronize the second
1053 * background disk thread's progress object with the current progress object so
1054 * that the user interface sees progress correctly and that cancel signals are
1055 * passed on to the second thread.
1056 *
1057 * @param pProgressThis Progress object of the current thread.
1058 * @param pProgressAsync Progress object of asynchronous task running in background.
1059 */
1060void Appliance::i_waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
1061 ComPtr<IProgress> &pProgressAsync)
1062{
1063 HRESULT rc;
1064
1065 // now loop until the asynchronous operation completes and then report its result
1066 BOOL fCompleted;
1067 BOOL fCanceled;
1068 ULONG currentPercent;
1069 ULONG cOp = 0;
1070 while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
1071 {
1072 rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
1073 if (FAILED(rc)) throw rc;
1074 if (fCanceled)
1075 pProgressAsync->Cancel();
1076 /* Check if the current operation has changed. It is also possible
1077 that in the meantime more than one async operation was finished. So
1078 we have to loop as long as we reached the same operation count. */
1079 ULONG curOp;
1080 for (;;)
1081 {
1082 rc = pProgressAsync->COMGETTER(Operation(&curOp));
1083 if (FAILED(rc)) throw rc;
1084 if (cOp != curOp)
1085 {
1086 Bstr bstr;
1087 ULONG currentWeight;
1088 rc = pProgressAsync->COMGETTER(OperationDescription(bstr.asOutParam()));
1089 if (FAILED(rc)) throw rc;
1090 rc = pProgressAsync->COMGETTER(OperationWeight(&currentWeight));
1091 if (FAILED(rc)) throw rc;
1092 rc = pProgressThis->SetNextOperation(bstr.raw(), currentWeight);
1093 if (FAILED(rc)) throw rc;
1094 ++cOp;
1095 }
1096 else
1097 break;
1098 }
1099
1100 rc = pProgressAsync->COMGETTER(OperationPercent(&currentPercent));
1101 if (FAILED(rc)) throw rc;
1102 pProgressThis->SetCurrentOperationProgress(currentPercent);
1103 if (fCompleted)
1104 break;
1105
1106 /* Make sure the loop is not too tight */
1107 rc = pProgressAsync->WaitForCompletion(100);
1108 if (FAILED(rc)) throw rc;
1109 }
1110 // report result of asynchronous operation
1111 LONG iRc;
1112 rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
1113 if (FAILED(rc)) throw rc;
1114
1115
1116 // if the thread of the progress object has an error, then
1117 // retrieve the error info from there, or it'll be lost
1118 if (FAILED(iRc))
1119 {
1120 ProgressErrorInfo info(pProgressAsync);
1121 Utf8Str str(info.getText());
1122 const char *pcsz = str.c_str();
1123 HRESULT rc2 = setError(iRc, pcsz);
1124 throw rc2;
1125 }
1126}
1127
1128void Appliance::i_addWarning(const char* aWarning, ...)
1129{
1130 try
1131 {
1132 va_list args;
1133 va_start(args, aWarning);
1134 Utf8Str str(aWarning, args);
1135 va_end(args);
1136 m->llWarnings.push_back(str);
1137 }
1138 catch (...)
1139 {
1140 AssertFailed();
1141 }
1142}
1143
1144/**
1145 * Refreshes the cDisks and ulTotalDisksMB members in the instance data.
1146 * Requires that virtual system descriptions are present.
1147 */
1148void Appliance::i_disksWeight()
1149{
1150 m->ulTotalDisksMB = 0;
1151 m->cDisks = 0;
1152 // weigh the disk images according to their sizes
1153 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
1154 for (it = m->virtualSystemDescriptions.begin();
1155 it != m->virtualSystemDescriptions.end();
1156 ++it)
1157 {
1158 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
1159 /* One for every hard disk of the Virtual System */
1160 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->i_findByType(VirtualSystemDescriptionType_HardDiskImage);
1161 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
1162 for (itH = avsdeHDs.begin();
1163 itH != avsdeHDs.end();
1164 ++itH)
1165 {
1166 const VirtualSystemDescriptionEntry *pHD = *itH;
1167 m->ulTotalDisksMB += pHD->ulSizeMB;
1168 ++m->cDisks;
1169 }
1170
1171 avsdeHDs = vsdescThis->i_findByType(VirtualSystemDescriptionType_CDROM);
1172 for (itH = avsdeHDs.begin();
1173 itH != avsdeHDs.end();
1174 ++itH)
1175 {
1176 const VirtualSystemDescriptionEntry *pHD = *itH;
1177 m->ulTotalDisksMB += pHD->ulSizeMB;
1178 ++m->cDisks;
1179 }
1180 }
1181
1182}
1183
1184void Appliance::i_parseBucket(Utf8Str &aPath, Utf8Str &aBucket)
1185{
1186 /* Buckets are S3 specific. So parse the bucket out of the file path */
1187 if (!aPath.startsWith("/"))
1188 throw setError(E_INVALIDARG,
1189 tr("The path '%s' must start with /"), aPath.c_str());
1190 size_t bpos = aPath.find("/", 1);
1191 if (bpos != Utf8Str::npos)
1192 {
1193 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
1194 aPath = aPath.substr(bpos); /* The rest of the file path */
1195 }
1196 /* If there is no bucket name provided reject it */
1197 if (aBucket.isEmpty())
1198 throw setError(E_INVALIDARG,
1199 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
1200}
1201
1202/**
1203 * Worker for TaskOVF::handler.
1204 *
1205 * The TaskOVF is started in Appliance::readImpl() and Appliance::importImpl()
1206 * and Appliance::writeImpl().
1207 *
1208 * This will in turn call Appliance::readFS() or Appliance::importFS() or
1209 * Appliance::writeFS().
1210 *
1211 * @thread pTask The task.
1212 */
1213/* static */ void Appliance::i_importOrExportThreadTask(TaskOVF *pTask)
1214{
1215 LogFlowFuncEnter();
1216 AssertReturnVoid(pTask);
1217
1218 Appliance *pAppliance = pTask->pAppliance;
1219 LogFlowFunc(("Appliance %p taskType=%d\n", pAppliance, pTask->taskType));
1220
1221 switch (pTask->taskType)
1222 {
1223 case TaskOVF::Read:
1224 pAppliance->m->resetReadData();
1225 if (pTask->locInfo.storageType == VFSType_File)
1226 pTask->rc = pAppliance->i_readFS(pTask);
1227 else
1228 pTask->rc = E_NOTIMPL;
1229 break;
1230
1231 case TaskOVF::Import:
1232 /** @todo allow overriding these? */
1233 if (!pAppliance->m->fSignatureValid && pAppliance->m->pbSignedDigest)
1234 pTask->rc = pAppliance->setError(E_FAIL, tr("The manifest signature for '%s' is not valid"),
1235 pTask->locInfo.strPath.c_str());
1236 else if (!pAppliance->m->fCertificateValid && pAppliance->m->pbSignedDigest)
1237 {
1238 if (pAppliance->m->strCertError.isNotEmpty())
1239 pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is not valid: %s"),
1240 pTask->locInfo.strPath.c_str(), pAppliance->m->strCertError.c_str());
1241 else
1242 pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is not valid"),
1243 pTask->locInfo.strPath.c_str());
1244 }
1245 // fusion does not consider this a show stopper (we've filed a warning during read).
1246 //else if (pAppliance->m->fCertificateMissingPath && pAppliance->m->pbSignedDigest)
1247 // pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is does not have a valid CA path"),
1248 // pTask->locInfo.strPath.c_str());
1249 else
1250 {
1251 if (pTask->locInfo.storageType == VFSType_File)
1252 pTask->rc = pAppliance->i_importFS(pTask);
1253 else
1254 pTask->rc = E_NOTIMPL;
1255 }
1256 break;
1257
1258 case TaskOVF::Write:
1259 if (pTask->locInfo.storageType == VFSType_File)
1260 pTask->rc = pAppliance->i_writeFS(pTask);
1261 else
1262 pTask->rc = E_NOTIMPL;
1263 break;
1264
1265 default:
1266 AssertFailed();
1267 pTask->rc = E_FAIL;
1268 break;
1269 }
1270
1271 if (!pTask->pProgress.isNull())
1272 pTask->pProgress->i_notifyComplete(pTask->rc);
1273
1274 LogFlowFuncLeave();
1275}
1276
1277/* static */ DECLCALLBACK(int) Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
1278{
1279 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
1280
1281 if ( pTask
1282 && !pTask->pProgress.isNull())
1283 {
1284 BOOL fCanceled;
1285 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
1286 if (fCanceled)
1287 return -1;
1288 pTask->pProgress->SetCurrentOperationProgress(uPercent);
1289 }
1290 return VINF_SUCCESS;
1291}
1292
1293void i_parseURI(Utf8Str strUri, LocationInfo &locInfo)
1294{
1295 /* Check the URI for the protocol */
1296 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
1297 {
1298 locInfo.storageType = VFSType_File;
1299 strUri = strUri.substr(sizeof("file://") - 1);
1300 }
1301 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
1302 {
1303 locInfo.storageType = VFSType_S3;
1304 strUri = strUri.substr(sizeof("SunCloud://") - 1);
1305 }
1306 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
1307 {
1308 locInfo.storageType = VFSType_S3;
1309 strUri = strUri.substr(sizeof("S3://") - 1);
1310 }
1311 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
1312 throw E_NOTIMPL;
1313
1314 /* Not necessary on a file based URI */
1315 if (locInfo.storageType != VFSType_File)
1316 {
1317 size_t uppos = strUri.find("@"); /* username:password combo */
1318 if (uppos != Utf8Str::npos)
1319 {
1320 locInfo.strUsername = strUri.substr(0, uppos);
1321 strUri = strUri.substr(uppos + 1);
1322 size_t upos = locInfo.strUsername.find(":");
1323 if (upos != Utf8Str::npos)
1324 {
1325 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
1326 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
1327 }
1328 }
1329 size_t hpos = strUri.find("/"); /* hostname part */
1330 if (hpos != Utf8Str::npos)
1331 {
1332 locInfo.strHostname = strUri.substr(0, hpos);
1333 strUri = strUri.substr(hpos);
1334 }
1335 }
1336
1337 locInfo.strPath = strUri;
1338}
1339
1340
1341////////////////////////////////////////////////////////////////////////////////
1342//
1343// IVirtualSystemDescription constructor / destructor
1344//
1345////////////////////////////////////////////////////////////////////////////////
1346
1347/**
1348 * COM initializer.
1349 * @return
1350 */
1351HRESULT VirtualSystemDescription::init()
1352{
1353 /* Enclose the state transition NotReady->InInit->Ready */
1354 AutoInitSpan autoInitSpan(this);
1355 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1356
1357 /* Initialize data */
1358 m = new Data();
1359 m->pConfig = NULL;
1360
1361 /* Confirm a successful initialization */
1362 autoInitSpan.setSucceeded();
1363 return S_OK;
1364}
1365
1366/**
1367* COM uninitializer.
1368*/
1369
1370void VirtualSystemDescription::uninit()
1371{
1372 if (m->pConfig)
1373 delete m->pConfig;
1374 delete m;
1375 m = NULL;
1376}
1377
1378
1379////////////////////////////////////////////////////////////////////////////////
1380//
1381// IVirtualSystemDescription public methods
1382//
1383////////////////////////////////////////////////////////////////////////////////
1384
1385/**
1386 * Public method implementation.
1387 */
1388HRESULT VirtualSystemDescription::getCount(ULONG *aCount)
1389{
1390 if (!aCount)
1391 return E_POINTER;
1392
1393 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1394
1395 *aCount = (ULONG)m->maDescriptions.size();
1396 return S_OK;
1397}
1398
1399/**
1400 * Public method implementation.
1401 */
1402HRESULT VirtualSystemDescription::getDescription(std::vector<VirtualSystemDescriptionType_T> &aTypes,
1403 std::vector<com::Utf8Str> &aRefs,
1404 std::vector<com::Utf8Str> &aOVFValues,
1405 std::vector<com::Utf8Str> &aVBoxValues,
1406 std::vector<com::Utf8Str> &aExtraConfigValues)
1407
1408{
1409 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1410 size_t c = m->maDescriptions.size();
1411 aTypes.resize(c);
1412 aRefs.resize(c);
1413 aOVFValues.resize(c);
1414 aVBoxValues.resize(c);
1415 aExtraConfigValues.resize(c);
1416
1417 for (size_t i = 0; i < c; i++)
1418 {
1419 const VirtualSystemDescriptionEntry &vsde = m->maDescriptions[i];
1420 aTypes[i] = vsde.type;
1421 aRefs[i] = vsde.strRef;
1422 aOVFValues[i] = vsde.strOvf;
1423 aVBoxValues[i] = vsde.strVBoxCurrent;
1424 aExtraConfigValues[i] = vsde.strExtraConfigCurrent;
1425 }
1426 return S_OK;
1427}
1428
1429/**
1430 * Public method implementation.
1431 */
1432HRESULT VirtualSystemDescription::getDescriptionByType(VirtualSystemDescriptionType_T aType,
1433 std::vector<VirtualSystemDescriptionType_T> &aTypes,
1434 std::vector<com::Utf8Str> &aRefs,
1435 std::vector<com::Utf8Str> &aOVFValues,
1436 std::vector<com::Utf8Str> &aVBoxValues,
1437 std::vector<com::Utf8Str> &aExtraConfigValues)
1438{
1439 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1440 std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType(aType);
1441
1442 size_t c = vsd.size();
1443 aTypes.resize(c);
1444 aRefs.resize(c);
1445 aOVFValues.resize(c);
1446 aVBoxValues.resize(c);
1447 aExtraConfigValues.resize(c);
1448
1449 size_t i = 0;
1450 for (list<VirtualSystemDescriptionEntry*>::const_iterator it = vsd.begin(); it != vsd.end(); ++it, ++i)
1451 {
1452 const VirtualSystemDescriptionEntry *vsde = (*it);
1453 aTypes[i] = vsde->type;
1454 aRefs[i] = vsde->strRef;
1455 aOVFValues[i] = vsde->strOvf;
1456 aVBoxValues[i] = vsde->strVBoxCurrent;
1457 aExtraConfigValues[i] = vsde->strExtraConfigCurrent;
1458 }
1459
1460 return S_OK;
1461}
1462
1463/**
1464 * Public method implementation.
1465 */
1466HRESULT VirtualSystemDescription::getValuesByType(VirtualSystemDescriptionType_T aType,
1467 VirtualSystemDescriptionValueType_T aWhich,
1468 std::vector<com::Utf8Str> &aValues)
1469{
1470 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1471
1472 std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType (aType);
1473 aValues.resize((ULONG)vsd.size());
1474
1475 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1476 size_t i = 0;
1477 for (it = vsd.begin();
1478 it != vsd.end();
1479 ++it, ++i)
1480 {
1481 const VirtualSystemDescriptionEntry *vsde = (*it);
1482
1483 Bstr bstr;
1484 switch (aWhich)
1485 {
1486 case VirtualSystemDescriptionValueType_Reference: aValues[i] = vsde->strRef; break;
1487 case VirtualSystemDescriptionValueType_Original: aValues[i] = vsde->strOvf; break;
1488 case VirtualSystemDescriptionValueType_Auto: aValues[i] = vsde->strVBoxCurrent; break;
1489 case VirtualSystemDescriptionValueType_ExtraConfig: aValues[i] = vsde->strExtraConfigCurrent; break;
1490#ifdef VBOX_WITH_XPCOM_CPP_ENUM_HACK
1491 case VirtualSystemDescriptionValueType_32BitHack: AssertFailedBreak(); /* (compiler warnings) */
1492#endif
1493 }
1494 }
1495
1496 return S_OK;
1497}
1498
1499/**
1500 * Public method implementation.
1501 */
1502HRESULT VirtualSystemDescription::setFinalValues(const std::vector<BOOL> &aEnabled,
1503 const std::vector<com::Utf8Str> &aVBoxValues,
1504 const std::vector<com::Utf8Str> &aExtraConfigValues)
1505{
1506#ifndef RT_OS_WINDOWS
1507 // NOREF(aEnabledSize);
1508#endif /* RT_OS_WINDOWS */
1509 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1510
1511 if ( (aEnabled.size() != m->maDescriptions.size())
1512 || (aVBoxValues.size() != m->maDescriptions.size())
1513 || (aExtraConfigValues.size() != m->maDescriptions.size())
1514 )
1515 return E_INVALIDARG;
1516
1517 size_t i = 0;
1518 for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1519 it != m->maDescriptions.end();
1520 ++it, ++i)
1521 {
1522 VirtualSystemDescriptionEntry& vsde = *it;
1523
1524 if (aEnabled[i])
1525 {
1526 vsde.strVBoxCurrent = aVBoxValues[i];
1527 vsde.strExtraConfigCurrent = aExtraConfigValues[i];
1528 }
1529 else
1530 vsde.type = VirtualSystemDescriptionType_Ignore;
1531 }
1532
1533 return S_OK;
1534}
1535
1536/**
1537 * Public method implementation.
1538 */
1539HRESULT VirtualSystemDescription::addDescription(VirtualSystemDescriptionType_T aType,
1540 const com::Utf8Str &aVBoxValue,
1541 const com::Utf8Str &aExtraConfigValue)
1542
1543{
1544 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1545 i_addEntry(aType, "", aVBoxValue, aVBoxValue, 0, aExtraConfigValue);
1546 return S_OK;
1547}
1548
1549/**
1550 * Internal method; adds a new description item to the member list.
1551 * @param aType Type of description for the new item.
1552 * @param strRef Reference item; only used with hard disk controllers.
1553 * @param aOvfValue Corresponding original value from OVF.
1554 * @param aVBoxValue Initial configuration value (can be overridden by caller with setFinalValues).
1555 * @param ulSizeMB Weight for IProgress
1556 * @param strExtraConfig Extra configuration; meaning dependent on type.
1557 */
1558void VirtualSystemDescription::i_addEntry(VirtualSystemDescriptionType_T aType,
1559 const Utf8Str &strRef,
1560 const Utf8Str &aOvfValue,
1561 const Utf8Str &aVBoxValue,
1562 uint32_t ulSizeMB,
1563 const Utf8Str &strExtraConfig /*= ""*/)
1564{
1565 VirtualSystemDescriptionEntry vsde;
1566 vsde.ulIndex = (uint32_t)m->maDescriptions.size(); // each entry gets an index so the client side can reference them
1567 vsde.type = aType;
1568 vsde.strRef = strRef;
1569 vsde.strOvf = aOvfValue;
1570 vsde.strVBoxSuggested // remember original value
1571 = vsde.strVBoxCurrent // and set current value which can be overridden by setFinalValues()
1572 = aVBoxValue;
1573 vsde.strExtraConfigSuggested
1574 = vsde.strExtraConfigCurrent
1575 = strExtraConfig;
1576 vsde.ulSizeMB = ulSizeMB;
1577
1578 vsde.skipIt = false;
1579
1580 m->maDescriptions.push_back(vsde);
1581}
1582
1583/**
1584 * Private method; returns a list of description items containing all the items from the member
1585 * description items of this virtual system that match the given type.
1586 */
1587std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::i_findByType(VirtualSystemDescriptionType_T aType)
1588{
1589 std::list<VirtualSystemDescriptionEntry*> vsd;
1590 for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1591 it != m->maDescriptions.end();
1592 ++it)
1593 {
1594 if (it->type == aType)
1595 vsd.push_back(&(*it));
1596 }
1597
1598 return vsd;
1599}
1600
1601/* Private method; delete all records from the list
1602 * m->llDescriptions that match the given type.
1603 */
1604void VirtualSystemDescription::i_removeByType(VirtualSystemDescriptionType_T aType)
1605{
1606 std::vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1607 while (it != m->maDescriptions.end())
1608 {
1609 if (it->type == aType)
1610 it = m->maDescriptions.erase(it);
1611 else
1612 ++it;
1613 }
1614}
1615
1616/**
1617 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1618 * the given reference ID. Useful when needing the controller for a particular
1619 * virtual disk.
1620 */
1621const VirtualSystemDescriptionEntry* VirtualSystemDescription::i_findControllerFromID(uint32_t id)
1622{
1623 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1624 vector<VirtualSystemDescriptionEntry>::const_iterator it;
1625 for (it = m->maDescriptions.begin();
1626 it != m->maDescriptions.end();
1627 ++it)
1628 {
1629 const VirtualSystemDescriptionEntry &d = *it;
1630 switch (d.type)
1631 {
1632 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1633 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1634 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1635 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1636 if (d.strRef == strRef)
1637 return &d;
1638 break;
1639 default: break; /* Shut up MSC. */
1640 }
1641 }
1642
1643 return NULL;
1644}
1645
1646/**
1647 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1648 * contains a <vbox:Machine> element. This method then attempts to parse that and
1649 * create a MachineConfigFile instance from it which is stored in this instance data
1650 * and can then be used to create a machine.
1651 *
1652 * This must only be called once per instance.
1653 *
1654 * This rethrows all XML and logic errors from MachineConfigFile.
1655 *
1656 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1657 * DOM tree.
1658 */
1659void VirtualSystemDescription::i_importVBoxMachineXML(const xml::ElementNode &elmMachine)
1660{
1661 settings::MachineConfigFile *pConfig = NULL;
1662
1663 Assert(m->pConfig == NULL);
1664
1665 try
1666 {
1667 pConfig = new settings::MachineConfigFile(NULL);
1668 pConfig->importMachineXML(elmMachine);
1669
1670 m->pConfig = pConfig;
1671 }
1672 catch (...)
1673 {
1674 if (pConfig)
1675 delete pConfig;
1676 throw;
1677 }
1678}
1679
1680/**
1681 * Returns the machine config created by importVBoxMachineXML() or NULL if there's none.
1682 */
1683const settings::MachineConfigFile* VirtualSystemDescription::i_getMachineConfig() const
1684{
1685 return m->pConfig;
1686}
1687
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