VirtualBox

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

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

ApplianceImpl: Signature and certificate validation updates.

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