VirtualBox

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

Last change on this file since 45434 was 45367, checked in by vboxsync, 12 years ago

Main: a couple of whitespace fixes

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