VirtualBox

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

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

ApplianceImpl.cpp: Removed empty doxygen return and param tags.

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