VirtualBox

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

Last change on this file since 72899 was 72899, checked in by vboxsync, 7 years ago

ApplianceImpl.cpp: Lose the silly applianceIONameMap and associated stuff since it's unused and should've been a tiny switch statement.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette