VirtualBox

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

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

Main: s/Vbox/VBox/g s/VB/VBox/g

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.0 KB
Line 
1/* $Id: ApplianceImpl.cpp 50196 2014-01-23 18:15:23Z 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.215389.xyz. 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 */
374STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
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(anAppliance);
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->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->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 *
1091 * @return
1092 */
1093int Appliance::TaskOVF::startThread()
1094{
1095 int vrc = RTThreadCreate(NULL, Appliance::i_taskThreadImportOrExport, this,
1096 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
1097 "Appliance::Task");
1098
1099 if (RT_FAILURE(vrc))
1100 return Appliance::i_setErrorStatic(E_FAIL,
1101 Utf8StrFmt("Could not create OVF task thread (%Rrc)\n", vrc));
1102
1103 return S_OK;
1104}
1105
1106/**
1107 * Thread function for the thread started in Appliance::readImpl() and Appliance::importImpl()
1108 * and Appliance::writeImpl().
1109 * This will in turn call Appliance::readFS() or Appliance::readS3() or Appliance::importFS()
1110 * or Appliance::importS3() or Appliance::writeFS() or Appliance::writeS3().
1111 *
1112 * @param aThread
1113 * @param pvUser
1114 */
1115/* static */
1116DECLCALLBACK(int) Appliance::i_taskThreadImportOrExport(RTTHREAD /* aThread */, void *pvUser)
1117{
1118 std::auto_ptr<TaskOVF> task(static_cast<TaskOVF*>(pvUser));
1119 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
1120
1121 Appliance *pAppliance = task->pAppliance;
1122
1123 LogFlowFuncEnter();
1124 LogFlowFunc(("Appliance %p\n", pAppliance));
1125
1126 HRESULT taskrc = S_OK;
1127
1128 switch (task->taskType)
1129 {
1130 case TaskOVF::Read:
1131 if (task->locInfo.storageType == VFSType_File)
1132 taskrc = pAppliance->i_readFS(task.get());
1133 else if (task->locInfo.storageType == VFSType_S3)
1134#ifdef VBOX_WITH_S3
1135 taskrc = pAppliance->i_readS3(task.get());
1136#else
1137 taskrc = VERR_NOT_IMPLEMENTED;
1138#endif
1139 break;
1140
1141 case TaskOVF::Import:
1142 if (task->locInfo.storageType == VFSType_File)
1143 taskrc = pAppliance->i_importFS(task.get());
1144 else if (task->locInfo.storageType == VFSType_S3)
1145#ifdef VBOX_WITH_S3
1146 taskrc = pAppliance->i_importS3(task.get());
1147#else
1148 taskrc = VERR_NOT_IMPLEMENTED;
1149#endif
1150 break;
1151
1152 case TaskOVF::Write:
1153 if (task->locInfo.storageType == VFSType_File)
1154 taskrc = pAppliance->i_writeFS(task.get());
1155 else if (task->locInfo.storageType == VFSType_S3)
1156#ifdef VBOX_WITH_S3
1157 taskrc = pAppliance->i_writeS3(task.get());
1158#else
1159 taskrc = VERR_NOT_IMPLEMENTED;
1160#endif
1161 break;
1162 }
1163
1164 task->rc = taskrc;
1165
1166 if (!task->pProgress.isNull())
1167 task->pProgress->notifyComplete(taskrc);
1168
1169 LogFlowFuncLeave();
1170
1171 return VINF_SUCCESS;
1172}
1173
1174/* static */
1175int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
1176{
1177 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
1178
1179 if ( pTask
1180 && !pTask->pProgress.isNull())
1181 {
1182 BOOL fCanceled;
1183 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
1184 if (fCanceled)
1185 return -1;
1186 pTask->pProgress->SetCurrentOperationProgress(uPercent);
1187 }
1188 return VINF_SUCCESS;
1189}
1190
1191void i_parseURI(Utf8Str strUri, LocationInfo &locInfo)
1192{
1193 /* Check the URI for the protocol */
1194 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
1195 {
1196 locInfo.storageType = VFSType_File;
1197 strUri = strUri.substr(sizeof("file://") - 1);
1198 }
1199 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
1200 {
1201 locInfo.storageType = VFSType_S3;
1202 strUri = strUri.substr(sizeof("SunCloud://") - 1);
1203 }
1204 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
1205 {
1206 locInfo.storageType = VFSType_S3;
1207 strUri = strUri.substr(sizeof("S3://") - 1);
1208 }
1209 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
1210 throw E_NOTIMPL;
1211
1212 /* Not necessary on a file based URI */
1213 if (locInfo.storageType != VFSType_File)
1214 {
1215 size_t uppos = strUri.find("@"); /* username:password combo */
1216 if (uppos != Utf8Str::npos)
1217 {
1218 locInfo.strUsername = strUri.substr(0, uppos);
1219 strUri = strUri.substr(uppos + 1);
1220 size_t upos = locInfo.strUsername.find(":");
1221 if (upos != Utf8Str::npos)
1222 {
1223 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
1224 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
1225 }
1226 }
1227 size_t hpos = strUri.find("/"); /* hostname part */
1228 if (hpos != Utf8Str::npos)
1229 {
1230 locInfo.strHostname = strUri.substr(0, hpos);
1231 strUri = strUri.substr(hpos);
1232 }
1233 }
1234
1235 locInfo.strPath = strUri;
1236}
1237
1238////////////////////////////////////////////////////////////////////////////////
1239//
1240// IVirtualSystemDescription constructor / destructor
1241//
1242////////////////////////////////////////////////////////////////////////////////
1243
1244
1245/**
1246 * COM initializer.
1247 * @return
1248 */
1249HRESULT VirtualSystemDescription::init()
1250{
1251 /* Enclose the state transition NotReady->InInit->Ready */
1252 AutoInitSpan autoInitSpan(this);
1253 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1254
1255 /* Initialize data */
1256 m = new Data();
1257 m->pConfig = NULL;
1258
1259 /* Confirm a successful initialization */
1260 autoInitSpan.setSucceeded();
1261 return S_OK;
1262}
1263
1264/**
1265* COM uninitializer.
1266*/
1267
1268void VirtualSystemDescription::uninit()
1269{
1270 if (m->pConfig)
1271 delete m->pConfig;
1272 delete m;
1273 m = NULL;
1274}
1275
1276////////////////////////////////////////////////////////////////////////////////
1277//
1278// IVirtualSystemDescription public methods
1279//
1280////////////////////////////////////////////////////////////////////////////////
1281
1282/**
1283 * Public method implementation.
1284 * @param
1285 * @return
1286 */
1287HRESULT VirtualSystemDescription::getCount(ULONG *aCount)
1288{
1289 if (!aCount)
1290 return E_POINTER;
1291
1292 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1293
1294 *aCount = (ULONG)m->maDescriptions.size();
1295 return S_OK;
1296}
1297
1298/**
1299 * Public method implementation.
1300 * @return
1301 */
1302HRESULT VirtualSystemDescription::getDescription(std::vector<VirtualSystemDescriptionType_T> &aTypes,
1303 std::vector<com::Utf8Str> &aRefs,
1304 std::vector<com::Utf8Str> &aOVFValues,
1305 std::vector<com::Utf8Str> &aVBoxValues,
1306 std::vector<com::Utf8Str> &aExtraConfigValues)
1307
1308{
1309 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1310 size_t c = m->maDescriptions.size();
1311 aTypes.resize(c);
1312 aRefs.resize(c);
1313 aOVFValues.resize(c);
1314 aVBoxValues.resize(c);
1315 aExtraConfigValues.resize(c);
1316
1317 for (size_t i = 0; i < c; i++)
1318 {
1319 const VirtualSystemDescriptionEntry &vsde = m->maDescriptions[i];
1320 aTypes[i] = vsde.type;
1321 aRefs[i] = vsde.strRef;
1322 aOVFValues[i] = vsde.strOvf;
1323 aVBoxValues[i] = vsde.strVBoxCurrent;
1324 aExtraConfigValues[i] = vsde.strExtraConfigCurrent;
1325 }
1326 return S_OK;
1327}
1328
1329/**
1330 * Public method implementation.
1331 * @return
1332 */
1333HRESULT VirtualSystemDescription::getDescriptionByType(VirtualSystemDescriptionType_T aType,
1334 std::vector<VirtualSystemDescriptionType_T> &aTypes,
1335 std::vector<com::Utf8Str> &aRefs,
1336 std::vector<com::Utf8Str> &aOVFValues,
1337 std::vector<com::Utf8Str> &aVBoxValues,
1338 std::vector<com::Utf8Str> &aExtraConfigValues)
1339{
1340 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1341 std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType(aType);
1342
1343 size_t c = vsd.size();
1344 aTypes.resize(c);
1345 aRefs.resize(c);
1346 aOVFValues.resize(c);
1347 aVBoxValues.resize(c);
1348 aExtraConfigValues.resize(c);
1349
1350 size_t i = 0;
1351 for (list<VirtualSystemDescriptionEntry*>::const_iterator it = vsd.begin(); it != vsd.end(); ++it, ++i)
1352 {
1353 const VirtualSystemDescriptionEntry *vsde = (*it);
1354 aTypes[i] = vsde->type;
1355 aRefs[i] = vsde->strRef;
1356 aOVFValues[i] = vsde->strOvf;
1357 aVBoxValues[i] = vsde->strVBoxCurrent;
1358 aExtraConfigValues[i] = vsde->strExtraConfigCurrent;
1359 }
1360
1361 return S_OK;
1362}
1363
1364/**
1365 * Public method implementation.
1366 * @return
1367 */
1368HRESULT VirtualSystemDescription::getValuesByType(VirtualSystemDescriptionType_T aType,
1369 VirtualSystemDescriptionValueType_T aWhich,
1370 std::vector<com::Utf8Str> &aValues)
1371{
1372 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1373
1374 std::list<VirtualSystemDescriptionEntry*> vsd = i_findByType (aType);
1375 aValues.resize((ULONG)vsd.size());
1376
1377 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1378 size_t i = 0;
1379 for (it = vsd.begin();
1380 it != vsd.end();
1381 ++it, ++i)
1382 {
1383 const VirtualSystemDescriptionEntry *vsde = (*it);
1384
1385 Bstr bstr;
1386 switch (aWhich)
1387 {
1388 case VirtualSystemDescriptionValueType_Reference: aValues[i] = vsde->strRef; break;
1389 case VirtualSystemDescriptionValueType_Original: aValues[i] = vsde->strOvf; break;
1390 case VirtualSystemDescriptionValueType_Auto: aValues[i] = vsde->strVBoxCurrent; break;
1391 case VirtualSystemDescriptionValueType_ExtraConfig: aValues[i] = vsde->strExtraConfigCurrent; break;
1392 }
1393 }
1394
1395 return S_OK;
1396}
1397
1398/**
1399 * Public method implementation.
1400 * @return
1401 */
1402HRESULT VirtualSystemDescription::setFinalValues(const std::vector<BOOL> &aEnabled,
1403 const std::vector<com::Utf8Str> &aVBoxValues,
1404 const std::vector<com::Utf8Str> &aExtraConfigValues)
1405{
1406#ifndef RT_OS_WINDOWS
1407 // NOREF(aEnabledSize);
1408#endif /* RT_OS_WINDOWS */
1409 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1410
1411 if ( (aEnabled.size() != m->maDescriptions.size())
1412 || (aVBoxValues.size() != m->maDescriptions.size())
1413 || (aExtraConfigValues.size() != m->maDescriptions.size())
1414 )
1415 return E_INVALIDARG;
1416
1417 size_t i = 0;
1418 for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1419 it != m->maDescriptions.end();
1420 ++it, ++i)
1421 {
1422 VirtualSystemDescriptionEntry& vsde = *it;
1423
1424 if (aEnabled[i])
1425 {
1426 vsde.strVBoxCurrent = aVBoxValues[i];
1427 vsde.strExtraConfigCurrent = aExtraConfigValues[i];
1428 }
1429 else
1430 vsde.type = VirtualSystemDescriptionType_Ignore;
1431 }
1432
1433 return S_OK;
1434}
1435
1436/**
1437 * Public method implementation.
1438 * @return
1439 */
1440HRESULT VirtualSystemDescription::addDescription(VirtualSystemDescriptionType_T aType,
1441 const com::Utf8Str &aVBoxValue,
1442 const com::Utf8Str &aExtraConfigValue)
1443
1444{
1445 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1446 i_addEntry(aType, "", aVBoxValue, aVBoxValue, 0, aExtraConfigValue);
1447 return S_OK;
1448}
1449
1450/**
1451 * Internal method; adds a new description item to the member list.
1452 * @param aType Type of description for the new item.
1453 * @param strRef Reference item; only used with hard disk controllers.
1454 * @param aOrigValue Corresponding original value from OVF.
1455 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
1456 * @param ulSizeMB Weight for IProgress
1457 * @param strExtraConfig Extra configuration; meaning dependent on type.
1458 */
1459void VirtualSystemDescription::i_addEntry(VirtualSystemDescriptionType_T aType,
1460 const Utf8Str &strRef,
1461 const Utf8Str &aOvfValue,
1462 const Utf8Str &aVBoxValue,
1463 uint32_t ulSizeMB,
1464 const Utf8Str &strExtraConfig /*= ""*/)
1465{
1466 VirtualSystemDescriptionEntry vsde;
1467 vsde.ulIndex = (uint32_t)m->maDescriptions.size(); // each entry gets an index so the client side can reference them
1468 vsde.type = aType;
1469 vsde.strRef = strRef;
1470 vsde.strOvf = aOvfValue;
1471 vsde.strVBoxSuggested // remember original value
1472 = vsde.strVBoxCurrent // and set current value which can be overridden by setFinalValues()
1473 = aVBoxValue;
1474 vsde.strExtraConfigSuggested
1475 = vsde.strExtraConfigCurrent
1476 = strExtraConfig;
1477 vsde.ulSizeMB = ulSizeMB;
1478
1479 m->maDescriptions.push_back(vsde);
1480}
1481
1482/**
1483 * Private method; returns a list of description items containing all the items from the member
1484 * description items of this virtual system that match the given type.
1485 * @param aType
1486 * @return
1487 */
1488std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::i_findByType(VirtualSystemDescriptionType_T aType)
1489{
1490 std::list<VirtualSystemDescriptionEntry*> vsd;
1491 for (vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1492 it != m->maDescriptions.end();
1493 ++it)
1494 {
1495 if (it->type == aType)
1496 vsd.push_back(&(*it));
1497 }
1498
1499 return vsd;
1500}
1501
1502/* Private method; delete all records from the list
1503 * m->llDescriptions that match the given type.
1504 * @param aType
1505 * @return
1506 */
1507void VirtualSystemDescription::i_removeByType(VirtualSystemDescriptionType_T aType)
1508{
1509 std::vector<VirtualSystemDescriptionEntry>::iterator it = m->maDescriptions.begin();
1510 while (it != m->maDescriptions.end())
1511 {
1512 if (it->type == aType)
1513 it = m->maDescriptions.erase(it);
1514 else
1515 ++it;
1516 }
1517}
1518
1519/**
1520 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1521 * the given reference ID. Useful when needing the controller for a particular
1522 * virtual disk.
1523 * @param id
1524 * @return
1525 */
1526const VirtualSystemDescriptionEntry* VirtualSystemDescription::i_findControllerFromID(uint32_t id)
1527{
1528 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1529 vector<VirtualSystemDescriptionEntry>::const_iterator it;
1530 for (it = m->maDescriptions.begin();
1531 it != m->maDescriptions.end();
1532 ++it)
1533 {
1534 const VirtualSystemDescriptionEntry &d = *it;
1535 switch (d.type)
1536 {
1537 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1538 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1539 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1540 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1541 if (d.strRef == strRef)
1542 return &d;
1543 break;
1544 }
1545 }
1546
1547 return NULL;
1548}
1549
1550/**
1551 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1552 * contains a <vbox:Machine> element. This method then attempts to parse that and
1553 * create a MachineConfigFile instance from it which is stored in this instance data
1554 * and can then be used to create a machine.
1555 *
1556 * This must only be called once per instance.
1557 *
1558 * This rethrows all XML and logic errors from MachineConfigFile.
1559 *
1560 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1561 * DOM tree.
1562 */
1563void VirtualSystemDescription::i_importVBoxMachineXML(const xml::ElementNode &elmMachine)
1564{
1565 settings::MachineConfigFile *pConfig = NULL;
1566
1567 Assert(m->pConfig == NULL);
1568
1569 try
1570 {
1571 pConfig = new settings::MachineConfigFile(NULL);
1572 pConfig->importMachineXML(elmMachine);
1573
1574 m->pConfig = pConfig;
1575 }
1576 catch (...)
1577 {
1578 if (pConfig)
1579 delete pConfig;
1580 throw;
1581 }
1582}
1583
1584/**
1585 * Returns the machine config created by importVBoxMachineXML() or NULL if there's none.
1586 * @return
1587 */
1588const settings::MachineConfigFile* VirtualSystemDescription::i_getMachineConfig() const
1589{
1590 return m->pConfig;
1591}
1592
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette