VirtualBox

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

Last change on this file since 46757 was 46581, checked in by vboxsync, 12 years ago

pr6022. the attribute xmlns is used in the element <Envelope> to get the version of OVF. cleaning up the code.

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