VirtualBox

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

Last change on this file since 74897 was 74217, checked in by vboxsync, 6 years ago

bugref:9152. Progress implementation. Rearranging the code.

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