VirtualBox

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

Last change on this file since 50447 was 50444, checked in by vboxsync, 11 years ago

pr7197. Deleting unneeded CDROMs from export configuration was replaced by skipping them.

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