VirtualBox

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

Last change on this file since 52615 was 50899, checked in by vboxsync, 11 years ago

remove changes that break up log and error strings, introduced in 92972

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