VirtualBox

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

Last change on this file since 57319 was 56864, checked in by vboxsync, 10 years ago

added two more OSX guest types

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 58.3 KB
Line 
1/* $Id: ApplianceImpl.cpp 56864 2015-07-08 13:01:44Z 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 va_list args;
1122 va_start(args, aWarning);
1123 Utf8Str str(aWarning, args);
1124 va_end(args);
1125 m->llWarnings.push_back(str);
1126}
1127
1128/**
1129 * Refreshes the cDisks and ulTotalDisksMB members in the instance data.
1130 * Requires that virtual system descriptions are present.
1131 */
1132void Appliance::i_disksWeight()
1133{
1134 m->ulTotalDisksMB = 0;
1135 m->cDisks = 0;
1136 // weigh the disk images according to their sizes
1137 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
1138 for (it = m->virtualSystemDescriptions.begin();
1139 it != m->virtualSystemDescriptions.end();
1140 ++it)
1141 {
1142 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
1143 /* One for every hard disk of the Virtual System */
1144 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->i_findByType(VirtualSystemDescriptionType_HardDiskImage);
1145 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
1146 for (itH = avsdeHDs.begin();
1147 itH != avsdeHDs.end();
1148 ++itH)
1149 {
1150 const VirtualSystemDescriptionEntry *pHD = *itH;
1151 m->ulTotalDisksMB += pHD->ulSizeMB;
1152 ++m->cDisks;
1153 }
1154
1155 avsdeHDs = vsdescThis->i_findByType(VirtualSystemDescriptionType_CDROM);
1156 for (itH = avsdeHDs.begin();
1157 itH != avsdeHDs.end();
1158 ++itH)
1159 {
1160 const VirtualSystemDescriptionEntry *pHD = *itH;
1161 m->ulTotalDisksMB += pHD->ulSizeMB;
1162 ++m->cDisks;
1163 }
1164 }
1165
1166}
1167
1168void Appliance::i_parseBucket(Utf8Str &aPath, Utf8Str &aBucket)
1169{
1170 /* Buckets are S3 specific. So parse the bucket out of the file path */
1171 if (!aPath.startsWith("/"))
1172 throw setError(E_INVALIDARG,
1173 tr("The path '%s' must start with /"), aPath.c_str());
1174 size_t bpos = aPath.find("/", 1);
1175 if (bpos != Utf8Str::npos)
1176 {
1177 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
1178 aPath = aPath.substr(bpos); /* The rest of the file path */
1179 }
1180 /* If there is no bucket name provided reject it */
1181 if (aBucket.isEmpty())
1182 throw setError(E_INVALIDARG,
1183 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
1184}
1185
1186/**
1187 * Starts the worker thread for the task.
1188 *
1189 * @return COM status code.
1190 */
1191HRESULT Appliance::TaskOVF::startThread()
1192{
1193 /* Pick a thread name suitable for logging (<= 8 chars). */
1194 const char *pszTaskNm;
1195 switch (taskType)
1196 {
1197 case TaskOVF::Read: pszTaskNm = "ApplRead"; break;
1198 case TaskOVF::Import: pszTaskNm = "ApplImp"; break;
1199 case TaskOVF::Write: pszTaskNm = "ApplWrit"; break;
1200 default: pszTaskNm = "ApplTask"; break;
1201 }
1202
1203 int vrc = RTThreadCreate(NULL, Appliance::i_taskThreadImportOrExport, this,
1204 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0, pszTaskNm);
1205 if (RT_SUCCESS(vrc))
1206 return S_OK;
1207 return Appliance::i_setErrorStatic(E_FAIL, Utf8StrFmt("Could not create OVF task thread (%Rrc)\n", vrc));
1208}
1209
1210/**
1211 * Thread function for the thread started in Appliance::readImpl() and Appliance::importImpl()
1212 * and Appliance::writeImpl().
1213 * This will in turn call Appliance::readFS() or Appliance::readS3() or Appliance::importFS()
1214 * or Appliance::importS3() or Appliance::writeFS() or Appliance::writeS3().
1215 *
1216 * @param aThread
1217 * @param pvUser
1218 */
1219/* static */
1220DECLCALLBACK(int) Appliance::i_taskThreadImportOrExport(RTTHREAD /* aThread */, void *pvUser)
1221{
1222 std::auto_ptr<TaskOVF> task(static_cast<TaskOVF*>(pvUser));
1223 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
1224
1225 Appliance *pAppliance = task->pAppliance;
1226
1227 LogFlowFuncEnter();
1228 LogFlowFunc(("Appliance %p taskType=%d\n", pAppliance, task->taskType));
1229
1230 HRESULT taskrc = S_OK;
1231
1232 switch (task->taskType)
1233 {
1234 case TaskOVF::Read:
1235 if (task->locInfo.storageType == VFSType_File)
1236 taskrc = pAppliance->i_readFS(task.get());
1237 else if (task->locInfo.storageType == VFSType_S3)
1238#ifdef VBOX_WITH_S3
1239 taskrc = pAppliance->i_readS3(task.get());
1240#else
1241 taskrc = VERR_NOT_IMPLEMENTED;
1242#endif
1243 break;
1244
1245 case TaskOVF::Import:
1246 if (task->locInfo.storageType == VFSType_File)
1247 taskrc = pAppliance->i_importFS(task.get());
1248 else if (task->locInfo.storageType == VFSType_S3)
1249#ifdef VBOX_WITH_S3
1250 taskrc = pAppliance->i_importS3(task.get());
1251#else
1252 taskrc = VERR_NOT_IMPLEMENTED;
1253#endif
1254 break;
1255
1256 case TaskOVF::Write:
1257 if (task->locInfo.storageType == VFSType_File)
1258 taskrc = pAppliance->i_writeFS(task.get());
1259 else if (task->locInfo.storageType == VFSType_S3)
1260#ifdef VBOX_WITH_S3
1261 taskrc = pAppliance->i_writeS3(task.get());
1262#else
1263 taskrc = VERR_NOT_IMPLEMENTED;
1264#endif
1265 break;
1266 }
1267
1268 task->rc = taskrc;
1269
1270 if (!task->pProgress.isNull())
1271 task->pProgress->i_notifyComplete(taskrc);
1272
1273 LogFlowFuncLeave();
1274
1275 return VINF_SUCCESS;
1276}
1277
1278/* static */
1279int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
1280{
1281 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
1282
1283 if ( pTask
1284 && !pTask->pProgress.isNull())
1285 {
1286 BOOL fCanceled;
1287 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
1288 if (fCanceled)
1289 return -1;
1290 pTask->pProgress->SetCurrentOperationProgress(uPercent);
1291 }
1292 return VINF_SUCCESS;
1293}
1294
1295void i_parseURI(Utf8Str strUri, LocationInfo &locInfo)
1296{
1297 /* Check the URI for the protocol */
1298 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
1299 {
1300 locInfo.storageType = VFSType_File;
1301 strUri = strUri.substr(sizeof("file://") - 1);
1302 }
1303 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
1304 {
1305 locInfo.storageType = VFSType_S3;
1306 strUri = strUri.substr(sizeof("SunCloud://") - 1);
1307 }
1308 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
1309 {
1310 locInfo.storageType = VFSType_S3;
1311 strUri = strUri.substr(sizeof("S3://") - 1);
1312 }
1313 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
1314 throw E_NOTIMPL;
1315
1316 /* Not necessary on a file based URI */
1317 if (locInfo.storageType != VFSType_File)
1318 {
1319 size_t uppos = strUri.find("@"); /* username:password combo */
1320 if (uppos != Utf8Str::npos)
1321 {
1322 locInfo.strUsername = strUri.substr(0, uppos);
1323 strUri = strUri.substr(uppos + 1);
1324 size_t upos = locInfo.strUsername.find(":");
1325 if (upos != Utf8Str::npos)
1326 {
1327 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
1328 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
1329 }
1330 }
1331 size_t hpos = strUri.find("/"); /* hostname part */
1332 if (hpos != Utf8Str::npos)
1333 {
1334 locInfo.strHostname = strUri.substr(0, hpos);
1335 strUri = strUri.substr(hpos);
1336 }
1337 }
1338
1339 locInfo.strPath = strUri;
1340}
1341
1342////////////////////////////////////////////////////////////////////////////////
1343//
1344// IVirtualSystemDescription constructor / destructor
1345//
1346////////////////////////////////////////////////////////////////////////////////
1347
1348
1349/**
1350 * COM initializer.
1351 * @return
1352 */
1353HRESULT VirtualSystemDescription::init()
1354{
1355 /* Enclose the state transition NotReady->InInit->Ready */
1356 AutoInitSpan autoInitSpan(this);
1357 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1358
1359 /* Initialize data */
1360 m = new Data();
1361 m->pConfig = NULL;
1362
1363 /* Confirm a successful initialization */
1364 autoInitSpan.setSucceeded();
1365 return S_OK;
1366}
1367
1368/**
1369* COM uninitializer.
1370*/
1371
1372void VirtualSystemDescription::uninit()
1373{
1374 if (m->pConfig)
1375 delete m->pConfig;
1376 delete m;
1377 m = NULL;
1378}
1379
1380////////////////////////////////////////////////////////////////////////////////
1381//
1382// IVirtualSystemDescription public methods
1383//
1384////////////////////////////////////////////////////////////////////////////////
1385
1386/**
1387 * Public method implementation.
1388 * @param
1389 * @return
1390 */
1391HRESULT VirtualSystemDescription::getCount(ULONG *aCount)
1392{
1393 if (!aCount)
1394 return E_POINTER;
1395
1396 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1397
1398 *aCount = (ULONG)m->maDescriptions.size();
1399 return S_OK;
1400}
1401
1402/**
1403 * Public method implementation.
1404 * @return
1405 */
1406HRESULT VirtualSystemDescription::getDescription(std::vector<VirtualSystemDescriptionType_T> &aTypes,
1407 std::vector<com::Utf8Str> &aRefs,
1408 std::vector<com::Utf8Str> &aOVFValues,
1409 std::vector<com::Utf8Str> &aVBoxValues,
1410 std::vector<com::Utf8Str> &aExtraConfigValues)
1411
1412{
1413 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1414 size_t c = m->maDescriptions.size();
1415 aTypes.resize(c);
1416 aRefs.resize(c);
1417 aOVFValues.resize(c);
1418 aVBoxValues.resize(c);
1419 aExtraConfigValues.resize(c);
1420
1421 for (size_t i = 0; i < c; i++)
1422 {
1423 const VirtualSystemDescriptionEntry &vsde = m->maDescriptions[i];
1424 aTypes[i] = vsde.type;
1425 aRefs[i] = vsde.strRef;
1426 aOVFValues[i] = vsde.strOvf;
1427 aVBoxValues[i] = vsde.strVBoxCurrent;
1428 aExtraConfigValues[i] = vsde.strExtraConfigCurrent;
1429 }
1430 return S_OK;
1431}
1432
1433/**
1434 * Public method implementation.
1435 * @return
1436 */
1437HRESULT VirtualSystemDescription::getDescriptionByType(VirtualSystemDescriptionType_T aType,
1438 std::vector<VirtualSystemDescriptionType_T> &aTypes,
1439 std::vector<com::Utf8Str> &aRefs,
1440 std::vector<com::Utf8Str> &aOVFValues,
1441 std::vector<com::Utf8Str> &aVBoxValues,
1442 std::vector<com::Utf8Str> &aExtraConfigValues)
1443{
1444 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1445 std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType(aType);
1446
1447 size_t c = vsd.size();
1448 aTypes.resize(c);
1449 aRefs.resize(c);
1450 aOVFValues.resize(c);
1451 aVBoxValues.resize(c);
1452 aExtraConfigValues.resize(c);
1453
1454 size_t i = 0;
1455 for (list<VirtualSystemDescriptionEntry*>::const_iterator it = vsd.begin(); it != vsd.end(); ++it, ++i)
1456 {
1457 const VirtualSystemDescriptionEntry *vsde = (*it);
1458 aTypes[i] = vsde->type;
1459 aRefs[i] = vsde->strRef;
1460 aOVFValues[i] = vsde->strOvf;
1461 aVBoxValues[i] = vsde->strVBoxCurrent;
1462 aExtraConfigValues[i] = vsde->strExtraConfigCurrent;
1463 }
1464
1465 return S_OK;
1466}
1467
1468/**
1469 * Public method implementation.
1470 * @return
1471 */
1472HRESULT VirtualSystemDescription::getValuesByType(VirtualSystemDescriptionType_T aType,
1473 VirtualSystemDescriptionValueType_T aWhich,
1474 std::vector<com::Utf8Str> &aValues)
1475{
1476 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1477
1478 std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType (aType);
1479 aValues.resize((ULONG)vsd.size());
1480
1481 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1482 size_t i = 0;
1483 for (it = vsd.begin();
1484 it != vsd.end();
1485 ++it, ++i)
1486 {
1487 const VirtualSystemDescriptionEntry *vsde = (*it);
1488
1489 Bstr bstr;
1490 switch (aWhich)
1491 {
1492 case VirtualSystemDescriptionValueType_Reference: aValues[i] = vsde->strRef; break;
1493 case VirtualSystemDescriptionValueType_Original: aValues[i] = vsde->strOvf; break;
1494 case VirtualSystemDescriptionValueType_Auto: aValues[i] = vsde->strVBoxCurrent; break;
1495 case VirtualSystemDescriptionValueType_ExtraConfig: aValues[i] = vsde->strExtraConfigCurrent; break;
1496 }
1497 }
1498
1499 return S_OK;
1500}
1501
1502/**
1503 * Public method implementation.
1504 * @return
1505 */
1506HRESULT VirtualSystemDescription::setFinalValues(const std::vector<BOOL> &aEnabled,
1507 const std::vector<com::Utf8Str> &aVBoxValues,
1508 const std::vector<com::Utf8Str> &aExtraConfigValues)
1509{
1510#ifndef RT_OS_WINDOWS
1511 // NOREF(aEnabledSize);
1512#endif /* RT_OS_WINDOWS */
1513 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1514
1515 if ( (aEnabled.size() != m->maDescriptions.size())
1516 || (aVBoxValues.size() != m->maDescriptions.size())
1517 || (aExtraConfigValues.size() != m->maDescriptions.size())
1518 )
1519 return E_INVALIDARG;
1520
1521 size_t i = 0;
1522 for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1523 it != m->maDescriptions.end();
1524 ++it, ++i)
1525 {
1526 VirtualSystemDescriptionEntry& vsde = *it;
1527
1528 if (aEnabled[i])
1529 {
1530 vsde.strVBoxCurrent = aVBoxValues[i];
1531 vsde.strExtraConfigCurrent = aExtraConfigValues[i];
1532 }
1533 else
1534 vsde.type = VirtualSystemDescriptionType_Ignore;
1535 }
1536
1537 return S_OK;
1538}
1539
1540/**
1541 * Public method implementation.
1542 * @return
1543 */
1544HRESULT VirtualSystemDescription::addDescription(VirtualSystemDescriptionType_T aType,
1545 const com::Utf8Str &aVBoxValue,
1546 const com::Utf8Str &aExtraConfigValue)
1547
1548{
1549 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1550 i_addEntry(aType, "", aVBoxValue, aVBoxValue, 0, aExtraConfigValue);
1551 return S_OK;
1552}
1553
1554/**
1555 * Internal method; adds a new description item to the member list.
1556 * @param aType Type of description for the new item.
1557 * @param strRef Reference item; only used with hard disk controllers.
1558 * @param aOrigValue Corresponding original value from OVF.
1559 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
1560 * @param ulSizeMB Weight for IProgress
1561 * @param strExtraConfig Extra configuration; meaning dependent on type.
1562 */
1563void VirtualSystemDescription::i_addEntry(VirtualSystemDescriptionType_T aType,
1564 const Utf8Str &strRef,
1565 const Utf8Str &aOvfValue,
1566 const Utf8Str &aVBoxValue,
1567 uint32_t ulSizeMB,
1568 const Utf8Str &strExtraConfig /*= ""*/)
1569{
1570 VirtualSystemDescriptionEntry vsde;
1571 vsde.ulIndex = (uint32_t)m->maDescriptions.size(); // each entry gets an index so the client side can reference them
1572 vsde.type = aType;
1573 vsde.strRef = strRef;
1574 vsde.strOvf = aOvfValue;
1575 vsde.strVBoxSuggested // remember original value
1576 = vsde.strVBoxCurrent // and set current value which can be overridden by setFinalValues()
1577 = aVBoxValue;
1578 vsde.strExtraConfigSuggested
1579 = vsde.strExtraConfigCurrent
1580 = strExtraConfig;
1581 vsde.ulSizeMB = ulSizeMB;
1582
1583 vsde.skipIt = false;
1584
1585 m->maDescriptions.push_back(vsde);
1586}
1587
1588/**
1589 * Private method; returns a list of description items containing all the items from the member
1590 * description items of this virtual system that match the given type.
1591 * @param aType
1592 * @return
1593 */
1594std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::i_findByType(VirtualSystemDescriptionType_T aType)
1595{
1596 std::list<VirtualSystemDescriptionEntry*> vsd;
1597 for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1598 it != m->maDescriptions.end();
1599 ++it)
1600 {
1601 if (it->type == aType)
1602 vsd.push_back(&(*it));
1603 }
1604
1605 return vsd;
1606}
1607
1608/* Private method; delete all records from the list
1609 * m->llDescriptions that match the given type.
1610 * @param aType
1611 * @return
1612 */
1613void VirtualSystemDescription::i_removeByType(VirtualSystemDescriptionType_T aType)
1614{
1615 std::vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1616 while (it != m->maDescriptions.end())
1617 {
1618 if (it->type == aType)
1619 it = m->maDescriptions.erase(it);
1620 else
1621 ++it;
1622 }
1623}
1624
1625/**
1626 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1627 * the given reference ID. Useful when needing the controller for a particular
1628 * virtual disk.
1629 * @param id
1630 * @return
1631 */
1632const VirtualSystemDescriptionEntry* VirtualSystemDescription::i_findControllerFromID(uint32_t id)
1633{
1634 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1635 vector<VirtualSystemDescriptionEntry>::const_iterator it;
1636 for (it = m->maDescriptions.begin();
1637 it != m->maDescriptions.end();
1638 ++it)
1639 {
1640 const VirtualSystemDescriptionEntry &d = *it;
1641 switch (d.type)
1642 {
1643 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1644 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1645 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1646 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1647 if (d.strRef == strRef)
1648 return &d;
1649 break;
1650 }
1651 }
1652
1653 return NULL;
1654}
1655
1656/**
1657 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1658 * contains a <vbox:Machine> element. This method then attempts to parse that and
1659 * create a MachineConfigFile instance from it which is stored in this instance data
1660 * and can then be used to create a machine.
1661 *
1662 * This must only be called once per instance.
1663 *
1664 * This rethrows all XML and logic errors from MachineConfigFile.
1665 *
1666 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1667 * DOM tree.
1668 */
1669void VirtualSystemDescription::i_importVBoxMachineXML(const xml::ElementNode &elmMachine)
1670{
1671 settings::MachineConfigFile *pConfig = NULL;
1672
1673 Assert(m->pConfig == NULL);
1674
1675 try
1676 {
1677 pConfig = new settings::MachineConfigFile(NULL);
1678 pConfig->importMachineXML(elmMachine);
1679
1680 m->pConfig = pConfig;
1681 }
1682 catch (...)
1683 {
1684 if (pConfig)
1685 delete pConfig;
1686 throw;
1687 }
1688}
1689
1690/**
1691 * Returns the machine config created by importVBoxMachineXML() or NULL if there's none.
1692 * @return
1693 */
1694const settings::MachineConfigFile* VirtualSystemDescription::i_getMachineConfig() const
1695{
1696 return m->pConfig;
1697}
1698
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