VirtualBox

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

Last change on this file since 62514 was 61003, checked in by vboxsync, 9 years ago

Main/Appliance: get rid of "Controller" in storage controller names (following the convention established in 4.x) for importing true OVF appliances, and clean up settings.h including, as it limits recompilation

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