VirtualBox

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

Last change on this file since 63563 was 63563, checked in by vboxsync, 8 years ago

scm: cleaning up todos

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