VirtualBox

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

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

backed out r118835 as it incorrectly updated the 'This file is based on' file headers.

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