VirtualBox

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

Last change on this file since 42994 was 42261, checked in by vboxsync, 12 years ago

enabled shared clipboard support for Linux hosts (guest=>host only)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.2 KB
Line 
1/* $Id: ApplianceImpl.cpp 42261 2012-07-20 13:27:47Z 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
276////////////////////////////////////////////////////////////////////////////////
277//
278// IVirtualBox public methods
279//
280////////////////////////////////////////////////////////////////////////////////
281
282// This code is here so we won't have to include the appliance headers in the
283// IVirtualBox implementation.
284
285/**
286 * Implementation for IVirtualBox::createAppliance.
287 *
288 * @param anAppliance IAppliance object created if S_OK is returned.
289 * @return S_OK or error.
290 */
291STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
292{
293 HRESULT rc;
294
295 ComObjPtr<Appliance> appliance;
296 appliance.createObject();
297 rc = appliance->init(this);
298
299 if (SUCCEEDED(rc))
300 appliance.queryInterfaceTo(anAppliance);
301
302 return rc;
303}
304
305////////////////////////////////////////////////////////////////////////////////
306//
307// Appliance constructor / destructor
308//
309////////////////////////////////////////////////////////////////////////////////
310
311Appliance::Appliance()
312 : mVirtualBox(NULL)
313{
314}
315
316Appliance::~Appliance()
317{
318}
319
320/**
321 * Appliance COM initializer.
322 * @param
323 * @return
324 */
325HRESULT Appliance::init(VirtualBox *aVirtualBox)
326{
327 /* Enclose the state transition NotReady->InInit->Ready */
328 AutoInitSpan autoInitSpan(this);
329 AssertReturn(autoInitSpan.isOk(), E_FAIL);
330
331 /* Weak reference to a VirtualBox object */
332 unconst(mVirtualBox) = aVirtualBox;
333
334 // initialize data
335 m = new Data;
336
337 /* Confirm a successful initialization */
338 autoInitSpan.setSucceeded();
339
340 return S_OK;
341}
342
343/**
344 * Appliance COM uninitializer.
345 * @return
346 */
347void Appliance::uninit()
348{
349 /* Enclose the state transition Ready->InUninit->NotReady */
350 AutoUninitSpan autoUninitSpan(this);
351 if (autoUninitSpan.uninitDone())
352 return;
353
354 delete m;
355 m = NULL;
356}
357
358////////////////////////////////////////////////////////////////////////////////
359//
360// IAppliance public methods
361//
362////////////////////////////////////////////////////////////////////////////////
363
364/**
365 * Public method implementation.
366 * @param
367 * @return
368 */
369STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
370{
371 if (!aPath)
372 return E_POINTER;
373
374 AutoCaller autoCaller(this);
375 if (FAILED(autoCaller.rc())) return autoCaller.rc();
376
377 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
378
379 if (!isApplianceIdle())
380 return E_ACCESSDENIED;
381
382 Bstr bstrPath(m->locInfo.strPath);
383 bstrPath.cloneTo(aPath);
384
385 return S_OK;
386}
387
388/**
389 * Public method implementation.
390 * @param
391 * @return
392 */
393STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
394{
395 CheckComArgOutSafeArrayPointerValid(aDisks);
396
397 AutoCaller autoCaller(this);
398 if (FAILED(autoCaller.rc())) return autoCaller.rc();
399
400 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
401
402 if (!isApplianceIdle())
403 return E_ACCESSDENIED;
404
405 if (m->pReader) // OVFReader instantiated?
406 {
407 size_t c = m->pReader->m_mapDisks.size();
408 com::SafeArray<BSTR> sfaDisks(c);
409
410 ovf::DiskImagesMap::const_iterator it;
411 size_t i = 0;
412 for (it = m->pReader->m_mapDisks.begin();
413 it != m->pReader->m_mapDisks.end();
414 ++it, ++i)
415 {
416 // create a string representing this disk
417 const ovf::DiskImage &d = it->second;
418 char *psz = NULL;
419 RTStrAPrintf(&psz,
420 "%s\t"
421 "%RI64\t"
422 "%RI64\t"
423 "%s\t"
424 "%s\t"
425 "%RI64\t"
426 "%RI64\t"
427 "%s",
428 d.strDiskId.c_str(),
429 d.iCapacity,
430 d.iPopulatedSize,
431 d.strFormat.c_str(),
432 d.strHref.c_str(),
433 d.iSize,
434 d.iChunkSize,
435 d.strCompression.c_str());
436 Utf8Str utf(psz);
437 Bstr bstr(utf);
438 // push to safearray
439 bstr.cloneTo(&sfaDisks[i]);
440 RTStrFree(psz);
441 }
442
443 sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
444 }
445
446 return S_OK;
447}
448
449/**
450 * Public method implementation.
451 * @param
452 * @return
453 */
454STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
455{
456 CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
457
458 AutoCaller autoCaller(this);
459 if (FAILED(autoCaller.rc())) return autoCaller.rc();
460
461 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
462
463 if (!isApplianceIdle())
464 return E_ACCESSDENIED;
465
466 SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
467 sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
468
469 return S_OK;
470}
471
472/**
473 * Public method implementation.
474 * @param aDisks
475 * @return
476 */
477STDMETHODIMP Appliance::COMGETTER(Machines)(ComSafeArrayOut(BSTR, aMachines))
478{
479 CheckComArgOutSafeArrayPointerValid(aMachines);
480
481 AutoCaller autoCaller(this);
482 if (FAILED(autoCaller.rc())) return autoCaller.rc();
483
484 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
485
486 if (!isApplianceIdle())
487 return E_ACCESSDENIED;
488
489 com::SafeArray<BSTR> sfaMachines(m->llGuidsMachinesCreated.size());
490 size_t u = 0;
491 for (std::list<Guid>::const_iterator it = m->llGuidsMachinesCreated.begin();
492 it != m->llGuidsMachinesCreated.end();
493 ++it)
494 {
495 const Guid &uuid = *it;
496 Bstr bstr(uuid.toUtf16());
497 bstr.detachTo(&sfaMachines[u]);
498 ++u;
499 }
500
501 sfaMachines.detachTo(ComSafeArrayOutArg(aMachines));
502
503 return S_OK;
504}
505
506STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
507{
508 CheckComArgOutPointerValid(aExplorer);
509
510 AutoCaller autoCaller(this);
511 if (FAILED(autoCaller.rc())) return autoCaller.rc();
512
513 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
514
515 ComObjPtr<VFSExplorer> explorer;
516 HRESULT rc = S_OK;
517 try
518 {
519 Utf8Str uri(aURI);
520 /* Check which kind of export the user has requested */
521 LocationInfo li;
522 parseURI(uri, li);
523 /* Create the explorer object */
524 explorer.createObject();
525 rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
526 }
527 catch (HRESULT aRC)
528 {
529 rc = aRC;
530 }
531
532 if (SUCCEEDED(rc))
533 /* Return explorer to the caller */
534 explorer.queryInterfaceTo(aExplorer);
535
536 return rc;
537}
538
539/**
540* Public method implementation.
541 * @return
542 */
543STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
544{
545 if (ComSafeArrayOutIsNull(aWarnings))
546 return E_POINTER;
547
548 AutoCaller autoCaller(this);
549 if (FAILED(autoCaller.rc())) return autoCaller.rc();
550
551 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
552
553 com::SafeArray<BSTR> sfaWarnings(m->llWarnings.size());
554
555 list<Utf8Str>::const_iterator it;
556 size_t i = 0;
557 for (it = m->llWarnings.begin();
558 it != m->llWarnings.end();
559 ++it, ++i)
560 {
561 Bstr bstr = *it;
562 bstr.cloneTo(&sfaWarnings[i]);
563 }
564
565 sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
566
567 return S_OK;
568}
569
570////////////////////////////////////////////////////////////////////////////////
571//
572// Appliance private methods
573//
574////////////////////////////////////////////////////////////////////////////////
575
576/**
577 * Returns true if the appliance is in "idle" state. This should always be the
578 * case unless an import or export is currently in progress. Similar to machine
579 * states, this permits the Appliance implementation code to let go of the
580 * Appliance object lock while a time-consuming disk conversion is in progress
581 * without exposing the appliance to conflicting calls.
582 *
583 * This sets an error on "this" (the appliance) and returns false if the appliance
584 * is busy. The caller should then return E_ACCESSDENIED.
585 *
586 * Must be called from under the object lock!
587 *
588 * @return
589 */
590bool Appliance::isApplianceIdle()
591{
592 if (m->state == Data::ApplianceImporting)
593 setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy importing files"));
594 else if (m->state == Data::ApplianceExporting)
595 setError(VBOX_E_INVALID_OBJECT_STATE, tr("The appliance is busy exporting files"));
596 else
597 return true;
598
599 return false;
600}
601
602HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
603{
604 IMachine *machine = NULL;
605 char *tmpName = RTStrDup(aName.c_str());
606 int i = 1;
607 /** @todo: Maybe too cost-intensive; try to find a lighter way */
608 while (mVirtualBox->FindMachine(Bstr(tmpName).raw(), &machine) != VBOX_E_OBJECT_NOT_FOUND)
609 {
610 RTStrFree(tmpName);
611 RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
612 ++i;
613 }
614 aName = tmpName;
615 RTStrFree(tmpName);
616
617 return S_OK;
618}
619
620HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
621{
622 IMedium *harddisk = NULL;
623 char *tmpName = RTStrDup(aName.c_str());
624 int i = 1;
625 /* Check if the file exists or if a file with this path is registered
626 * already */
627 /** @todo: Maybe too cost-intensive; try to find a lighter way */
628 while ( RTPathExists(tmpName)
629 || mVirtualBox->OpenMedium(Bstr(tmpName).raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE /* fForceNewUuid */, &harddisk) != VBOX_E_OBJECT_NOT_FOUND
630 )
631 {
632 RTStrFree(tmpName);
633 char *tmpDir = RTStrDup(aName.c_str());
634 RTPathStripFilename(tmpDir);;
635 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
636 RTPathStripExt(tmpFile);
637 const char *tmpExt = RTPathExt(aName.c_str());
638 RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
639 RTStrFree(tmpFile);
640 RTStrFree(tmpDir);
641 ++i;
642 }
643 aName = tmpName;
644 RTStrFree(tmpName);
645
646 return S_OK;
647}
648
649/**
650 * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a
651 * progress object with the proper weights and maximum progress values.
652 *
653 * @param pProgress
654 * @param bstrDescription
655 * @param mode
656 * @return
657 */
658HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress,
659 const Bstr &bstrDescription,
660 SetUpProgressMode mode)
661{
662 HRESULT rc;
663
664 /* Create the progress object */
665 pProgress.createObject();
666
667 // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data)
668 disksWeight();
669
670 m->ulWeightForManifestOperation = 0;
671
672 ULONG cOperations;
673 ULONG ulTotalOperationsWeight;
674
675 cOperations = 1 // one for XML setup
676 + m->cDisks; // plus one per disk
677 if (m->ulTotalDisksMB)
678 {
679 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML
680 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
681 }
682 else
683 {
684 // no disks to export:
685 m->ulWeightForXmlOperation = 1;
686 ulTotalOperationsWeight = 1;
687 }
688
689 switch (mode)
690 {
691 case ImportFile:
692 {
693 break;
694 }
695 case WriteFile:
696 {
697 // assume that creating the manifest will take .1% of the time it takes to export the disks
698 if (m->fManifest)
699 {
700 ++cOperations; // another one for creating the manifest
701
702 m->ulWeightForManifestOperation = (ULONG)((double)m->ulTotalDisksMB * .1 / 100); // use .5% of the progress for the manifest
703 ulTotalOperationsWeight += m->ulWeightForManifestOperation;
704 }
705 break;
706 }
707 case ImportS3:
708 {
709 cOperations += 1 + 1; // another one for the manifest file & another one for the import
710 ulTotalOperationsWeight = m->ulTotalDisksMB;
711 if (!m->ulTotalDisksMB)
712 // no disks to export:
713 ulTotalOperationsWeight = 1;
714
715 ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import
716 ulTotalOperationsWeight += ulImportWeight;
717
718 m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */
719
720 ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init
721 ulTotalOperationsWeight += ulInitWeight;
722 break;
723 }
724 case WriteS3:
725 {
726 cOperations += 1 + 1; // another one for the mf & another one for temporary creation
727
728 if (m->ulTotalDisksMB)
729 {
730 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)
731 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
732 }
733 else
734 {
735 // no disks to export:
736 ulTotalOperationsWeight = 1;
737 m->ulWeightForXmlOperation = 1;
738 }
739 ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
740 ulTotalOperationsWeight += ulOVFCreationWeight;
741 break;
742 }
743 }
744
745 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n",
746 m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation));
747
748 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
749 bstrDescription.raw(),
750 TRUE /* aCancelable */,
751 cOperations, // ULONG cOperations,
752 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
753 bstrDescription.raw(), // CBSTR bstrFirstOperationDescription,
754 m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight,
755 return rc;
756}
757
758/**
759 * Called from the import and export background threads to synchronize the second
760 * background disk thread's progress object with the current progress object so
761 * that the user interface sees progress correctly and that cancel signals are
762 * passed on to the second thread.
763 * @param pProgressThis Progress object of the current thread.
764 * @param pProgressAsync Progress object of asynchronous task running in background.
765 */
766void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
767 ComPtr<IProgress> &pProgressAsync)
768{
769 HRESULT rc;
770
771 // now loop until the asynchronous operation completes and then report its result
772 BOOL fCompleted;
773 BOOL fCanceled;
774 ULONG currentPercent;
775 ULONG cOp = 0;
776 while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
777 {
778 rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
779 if (FAILED(rc)) throw rc;
780 if (fCanceled)
781 pProgressAsync->Cancel();
782 /* Check if the current operation has changed. It is also possible
783 that in the meantime more than one async operation was finished. So
784 we have to loop as long as we reached the same operation count. */
785 ULONG curOp;
786 for(;;)
787 {
788 rc = pProgressAsync->COMGETTER(Operation(&curOp));
789 if (FAILED(rc)) throw rc;
790 if (cOp != curOp)
791 {
792 Bstr bstr;
793 ULONG currentWeight;
794 rc = pProgressAsync->COMGETTER(OperationDescription(bstr.asOutParam()));
795 if (FAILED(rc)) throw rc;
796 rc = pProgressAsync->COMGETTER(OperationWeight(&currentWeight));
797 if (FAILED(rc)) throw rc;
798 rc = pProgressThis->SetNextOperation(bstr.raw(), currentWeight);
799 if (FAILED(rc)) throw rc;
800 ++cOp;
801 }
802 else
803 break;
804 }
805
806 rc = pProgressAsync->COMGETTER(OperationPercent(&currentPercent));
807 if (FAILED(rc)) throw rc;
808 pProgressThis->SetCurrentOperationProgress(currentPercent);
809 if (fCompleted)
810 break;
811
812 /* Make sure the loop is not too tight */
813 rc = pProgressAsync->WaitForCompletion(100);
814 if (FAILED(rc)) throw rc;
815 }
816 // report result of asynchronous operation
817 LONG iRc;
818 rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
819 if (FAILED(rc)) throw rc;
820
821
822 // if the thread of the progress object has an error, then
823 // retrieve the error info from there, or it'll be lost
824 if (FAILED(iRc))
825 {
826 ProgressErrorInfo info(pProgressAsync);
827 Utf8Str str(info.getText());
828 const char *pcsz = str.c_str();
829 HRESULT rc2 = setError(iRc, pcsz);
830 throw rc2;
831 }
832}
833
834void Appliance::addWarning(const char* aWarning, ...)
835{
836 va_list args;
837 va_start(args, aWarning);
838 Utf8Str str(aWarning, args);
839 va_end(args);
840 m->llWarnings.push_back(str);
841}
842
843/**
844 * Refreshes the cDisks and ulTotalDisksMB members in the instance data.
845 * Requires that virtual system descriptions are present.
846 */
847void Appliance::disksWeight()
848{
849 m->ulTotalDisksMB = 0;
850 m->cDisks = 0;
851 // weigh the disk images according to their sizes
852 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
853 for (it = m->virtualSystemDescriptions.begin();
854 it != m->virtualSystemDescriptions.end();
855 ++it)
856 {
857 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
858 /* One for every hard disk of the Virtual System */
859 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
860 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
861 for (itH = avsdeHDs.begin();
862 itH != avsdeHDs.end();
863 ++itH)
864 {
865 const VirtualSystemDescriptionEntry *pHD = *itH;
866 m->ulTotalDisksMB += pHD->ulSizeMB;
867 ++m->cDisks;
868 }
869 }
870
871}
872
873void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket)
874{
875 /* Buckets are S3 specific. So parse the bucket out of the file path */
876 if (!aPath.startsWith("/"))
877 throw setError(E_INVALIDARG,
878 tr("The path '%s' must start with /"), aPath.c_str());
879 size_t bpos = aPath.find("/", 1);
880 if (bpos != Utf8Str::npos)
881 {
882 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
883 aPath = aPath.substr(bpos); /* The rest of the file path */
884 }
885 /* If there is no bucket name provided reject it */
886 if (aBucket.isEmpty())
887 throw setError(E_INVALIDARG,
888 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
889}
890
891/**
892 *
893 * @return
894 */
895int Appliance::TaskOVF::startThread()
896{
897 int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOrExport, this,
898 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
899 "Appliance::Task");
900
901 if (RT_FAILURE(vrc))
902 return Appliance::setErrorStatic(E_FAIL,
903 Utf8StrFmt("Could not create OVF task thread (%Rrc)\n", vrc));
904
905 return S_OK;
906}
907
908/**
909 * Thread function for the thread started in Appliance::readImpl() and Appliance::importImpl()
910 * and Appliance::writeImpl().
911 * This will in turn call Appliance::readFS() or Appliance::readS3() or Appliance::importFS()
912 * or Appliance::importS3() or Appliance::writeFS() or Appliance::writeS3().
913 *
914 * @param aThread
915 * @param pvUser
916 */
917/* static */
918DECLCALLBACK(int) Appliance::taskThreadImportOrExport(RTTHREAD /* aThread */, void *pvUser)
919{
920 std::auto_ptr<TaskOVF> task(static_cast<TaskOVF*>(pvUser));
921 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
922
923 Appliance *pAppliance = task->pAppliance;
924
925 LogFlowFuncEnter();
926 LogFlowFunc(("Appliance %p\n", pAppliance));
927
928 HRESULT taskrc = S_OK;
929
930 switch (task->taskType)
931 {
932 case TaskOVF::Read:
933 if (task->locInfo.storageType == VFSType_File)
934 taskrc = pAppliance->readFS(task.get());
935 else if (task->locInfo.storageType == VFSType_S3)
936#ifdef VBOX_WITH_S3
937 taskrc = pAppliance->readS3(task.get());
938#else
939 taskrc = VERR_NOT_IMPLEMENTED;
940#endif
941 break;
942
943 case TaskOVF::Import:
944 if (task->locInfo.storageType == VFSType_File)
945 taskrc = pAppliance->importFS(task.get());
946 else if (task->locInfo.storageType == VFSType_S3)
947#ifdef VBOX_WITH_S3
948 taskrc = pAppliance->importS3(task.get());
949#else
950 taskrc = VERR_NOT_IMPLEMENTED;
951#endif
952 break;
953
954 case TaskOVF::Write:
955 if (task->locInfo.storageType == VFSType_File)
956 taskrc = pAppliance->writeFS(task.get());
957 else if (task->locInfo.storageType == VFSType_S3)
958#ifdef VBOX_WITH_S3
959 taskrc = pAppliance->writeS3(task.get());
960#else
961 taskrc = VERR_NOT_IMPLEMENTED;
962#endif
963 break;
964 }
965
966 task->rc = taskrc;
967
968 if (!task->pProgress.isNull())
969 task->pProgress->notifyComplete(taskrc);
970
971 LogFlowFuncLeave();
972
973 return VINF_SUCCESS;
974}
975
976/* static */
977int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
978{
979 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
980
981 if ( pTask
982 && !pTask->pProgress.isNull())
983 {
984 BOOL fCanceled;
985 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
986 if (fCanceled)
987 return -1;
988 pTask->pProgress->SetCurrentOperationProgress(uPercent);
989 }
990 return VINF_SUCCESS;
991}
992
993void parseURI(Utf8Str strUri, LocationInfo &locInfo)
994{
995 /* Check the URI for the protocol */
996 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
997 {
998 locInfo.storageType = VFSType_File;
999 strUri = strUri.substr(sizeof("file://") - 1);
1000 }
1001 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
1002 {
1003 locInfo.storageType = VFSType_S3;
1004 strUri = strUri.substr(sizeof("SunCloud://") - 1);
1005 }
1006 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
1007 {
1008 locInfo.storageType = VFSType_S3;
1009 strUri = strUri.substr(sizeof("S3://") - 1);
1010 }
1011 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
1012 throw E_NOTIMPL;
1013
1014 /* Not necessary on a file based URI */
1015 if (locInfo.storageType != VFSType_File)
1016 {
1017 size_t uppos = strUri.find("@"); /* username:password combo */
1018 if (uppos != Utf8Str::npos)
1019 {
1020 locInfo.strUsername = strUri.substr(0, uppos);
1021 strUri = strUri.substr(uppos + 1);
1022 size_t upos = locInfo.strUsername.find(":");
1023 if (upos != Utf8Str::npos)
1024 {
1025 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
1026 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
1027 }
1028 }
1029 size_t hpos = strUri.find("/"); /* hostname part */
1030 if (hpos != Utf8Str::npos)
1031 {
1032 locInfo.strHostname = strUri.substr(0, hpos);
1033 strUri = strUri.substr(hpos);
1034 }
1035 }
1036
1037 locInfo.strPath = strUri;
1038}
1039
1040////////////////////////////////////////////////////////////////////////////////
1041//
1042// IVirtualSystemDescription constructor / destructor
1043//
1044////////////////////////////////////////////////////////////////////////////////
1045
1046DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
1047
1048/**
1049 * COM initializer.
1050 * @return
1051 */
1052HRESULT VirtualSystemDescription::init()
1053{
1054 /* Enclose the state transition NotReady->InInit->Ready */
1055 AutoInitSpan autoInitSpan(this);
1056 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1057
1058 /* Initialize data */
1059 m = new Data();
1060 m->pConfig = NULL;
1061
1062 /* Confirm a successful initialization */
1063 autoInitSpan.setSucceeded();
1064 return S_OK;
1065}
1066
1067/**
1068* COM uninitializer.
1069*/
1070
1071void VirtualSystemDescription::uninit()
1072{
1073 if (m->pConfig)
1074 delete m->pConfig;
1075 delete m;
1076 m = NULL;
1077}
1078
1079////////////////////////////////////////////////////////////////////////////////
1080//
1081// IVirtualSystemDescription public methods
1082//
1083////////////////////////////////////////////////////////////////////////////////
1084
1085/**
1086 * Public method implementation.
1087 * @param
1088 * @return
1089 */
1090STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
1091{
1092 if (!aCount)
1093 return E_POINTER;
1094
1095 AutoCaller autoCaller(this);
1096 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1097
1098 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1099
1100 *aCount = (ULONG)m->llDescriptions.size();
1101
1102 return S_OK;
1103}
1104
1105/**
1106 * Public method implementation.
1107 * @return
1108 */
1109STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1110 ComSafeArrayOut(BSTR, aRefs),
1111 ComSafeArrayOut(BSTR, aOrigValues),
1112 ComSafeArrayOut(BSTR, aVboxValues),
1113 ComSafeArrayOut(BSTR, aExtraConfigValues))
1114{
1115 if (ComSafeArrayOutIsNull(aTypes) ||
1116 ComSafeArrayOutIsNull(aRefs) ||
1117 ComSafeArrayOutIsNull(aOrigValues) ||
1118 ComSafeArrayOutIsNull(aVboxValues) ||
1119 ComSafeArrayOutIsNull(aExtraConfigValues))
1120 return E_POINTER;
1121
1122 AutoCaller autoCaller(this);
1123 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1124
1125 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1126
1127 ULONG c = (ULONG)m->llDescriptions.size();
1128 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1129 com::SafeArray<BSTR> sfaRefs(c);
1130 com::SafeArray<BSTR> sfaOrigValues(c);
1131 com::SafeArray<BSTR> sfaVboxValues(c);
1132 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1133
1134 list<VirtualSystemDescriptionEntry>::const_iterator it;
1135 size_t i = 0;
1136 for (it = m->llDescriptions.begin();
1137 it != m->llDescriptions.end();
1138 ++it, ++i)
1139 {
1140 const VirtualSystemDescriptionEntry &vsde = (*it);
1141
1142 sfaTypes[i] = vsde.type;
1143
1144 Bstr bstr = vsde.strRef;
1145 bstr.cloneTo(&sfaRefs[i]);
1146
1147 bstr = vsde.strOvf;
1148 bstr.cloneTo(&sfaOrigValues[i]);
1149
1150 bstr = vsde.strVboxCurrent;
1151 bstr.cloneTo(&sfaVboxValues[i]);
1152
1153 bstr = vsde.strExtraConfigCurrent;
1154 bstr.cloneTo(&sfaExtraConfigValues[i]);
1155 }
1156
1157 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1158 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1159 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1160 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1161 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1162
1163 return S_OK;
1164}
1165
1166/**
1167 * Public method implementation.
1168 * @return
1169 */
1170STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescriptionType_T aType,
1171 ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1172 ComSafeArrayOut(BSTR, aRefs),
1173 ComSafeArrayOut(BSTR, aOrigValues),
1174 ComSafeArrayOut(BSTR, aVboxValues),
1175 ComSafeArrayOut(BSTR, aExtraConfigValues))
1176{
1177 if (ComSafeArrayOutIsNull(aTypes) ||
1178 ComSafeArrayOutIsNull(aRefs) ||
1179 ComSafeArrayOutIsNull(aOrigValues) ||
1180 ComSafeArrayOutIsNull(aVboxValues) ||
1181 ComSafeArrayOutIsNull(aExtraConfigValues))
1182 return E_POINTER;
1183
1184 AutoCaller autoCaller(this);
1185 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1186
1187 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1188
1189 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1190 ULONG c = (ULONG)vsd.size();
1191 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1192 com::SafeArray<BSTR> sfaRefs(c);
1193 com::SafeArray<BSTR> sfaOrigValues(c);
1194 com::SafeArray<BSTR> sfaVboxValues(c);
1195 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1196
1197 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1198 size_t i = 0;
1199 for (it = vsd.begin();
1200 it != vsd.end();
1201 ++it, ++i)
1202 {
1203 const VirtualSystemDescriptionEntry *vsde = (*it);
1204
1205 sfaTypes[i] = vsde->type;
1206
1207 Bstr bstr = vsde->strRef;
1208 bstr.cloneTo(&sfaRefs[i]);
1209
1210 bstr = vsde->strOvf;
1211 bstr.cloneTo(&sfaOrigValues[i]);
1212
1213 bstr = vsde->strVboxCurrent;
1214 bstr.cloneTo(&sfaVboxValues[i]);
1215
1216 bstr = vsde->strExtraConfigCurrent;
1217 bstr.cloneTo(&sfaExtraConfigValues[i]);
1218 }
1219
1220 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1221 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1222 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1223 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1224 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1225
1226 return S_OK;
1227}
1228
1229/**
1230 * Public method implementation.
1231 * @return
1232 */
1233STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionType_T aType,
1234 VirtualSystemDescriptionValueType_T aWhich,
1235 ComSafeArrayOut(BSTR, aValues))
1236{
1237 if (ComSafeArrayOutIsNull(aValues))
1238 return E_POINTER;
1239
1240 AutoCaller autoCaller(this);
1241 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1242
1243 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1244
1245 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1246 com::SafeArray<BSTR> sfaValues((ULONG)vsd.size());
1247
1248 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1249 size_t i = 0;
1250 for (it = vsd.begin();
1251 it != vsd.end();
1252 ++it, ++i)
1253 {
1254 const VirtualSystemDescriptionEntry *vsde = (*it);
1255
1256 Bstr bstr;
1257 switch (aWhich)
1258 {
1259 case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
1260 case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
1261 case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVboxCurrent; break;
1262 case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfigCurrent; break;
1263 }
1264
1265 bstr.cloneTo(&sfaValues[i]);
1266 }
1267
1268 sfaValues.detachTo(ComSafeArrayOutArg(aValues));
1269
1270 return S_OK;
1271}
1272
1273/**
1274 * Public method implementation.
1275 * @return
1276 */
1277STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
1278 ComSafeArrayIn(IN_BSTR, argVboxValues),
1279 ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
1280{
1281#ifndef RT_OS_WINDOWS
1282 NOREF(aEnabledSize);
1283#endif /* RT_OS_WINDOWS */
1284
1285 CheckComArgSafeArrayNotNull(aEnabled);
1286 CheckComArgSafeArrayNotNull(argVboxValues);
1287 CheckComArgSafeArrayNotNull(argExtraConfigValues);
1288
1289 AutoCaller autoCaller(this);
1290 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1291
1292 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1293
1294 com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
1295 com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
1296 com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
1297
1298 if ( (sfaEnabled.size() != m->llDescriptions.size())
1299 || (sfaVboxValues.size() != m->llDescriptions.size())
1300 || (sfaExtraConfigValues.size() != m->llDescriptions.size())
1301 )
1302 return E_INVALIDARG;
1303
1304 list<VirtualSystemDescriptionEntry>::iterator it;
1305 size_t i = 0;
1306 for (it = m->llDescriptions.begin();
1307 it != m->llDescriptions.end();
1308 ++it, ++i)
1309 {
1310 VirtualSystemDescriptionEntry& vsde = *it;
1311
1312 if (sfaEnabled[i])
1313 {
1314 vsde.strVboxCurrent = sfaVboxValues[i];
1315 vsde.strExtraConfigCurrent = sfaExtraConfigValues[i];
1316 }
1317 else
1318 vsde.type = VirtualSystemDescriptionType_Ignore;
1319 }
1320
1321 return S_OK;
1322}
1323
1324/**
1325 * Public method implementation.
1326 * @return
1327 */
1328STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
1329 IN_BSTR aVboxValue,
1330 IN_BSTR aExtraConfigValue)
1331{
1332 AutoCaller autoCaller(this);
1333 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1334
1335 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1336
1337 addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
1338
1339 return S_OK;
1340}
1341
1342/**
1343 * Internal method; adds a new description item to the member list.
1344 * @param aType Type of description for the new item.
1345 * @param strRef Reference item; only used with hard disk controllers.
1346 * @param aOrigValue Corresponding original value from OVF.
1347 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
1348 * @param ulSizeMB Weight for IProgress
1349 * @param strExtraConfig Extra configuration; meaning dependent on type.
1350 */
1351void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
1352 const Utf8Str &strRef,
1353 const Utf8Str &aOvfValue,
1354 const Utf8Str &aVboxValue,
1355 uint32_t ulSizeMB,
1356 const Utf8Str &strExtraConfig /*= ""*/)
1357{
1358 VirtualSystemDescriptionEntry vsde;
1359 vsde.ulIndex = (uint32_t)m->llDescriptions.size(); // each entry gets an index so the client side can reference them
1360 vsde.type = aType;
1361 vsde.strRef = strRef;
1362 vsde.strOvf = aOvfValue;
1363 vsde.strVboxSuggested // remember original value
1364 = vsde.strVboxCurrent // and set current value which can be overridden by setFinalValues()
1365 = aVboxValue;
1366 vsde.strExtraConfigSuggested
1367 = vsde.strExtraConfigCurrent
1368 = strExtraConfig;
1369 vsde.ulSizeMB = ulSizeMB;
1370
1371 m->llDescriptions.push_back(vsde);
1372}
1373
1374/**
1375 * Private method; returns a list of description items containing all the items from the member
1376 * description items of this virtual system that match the given type.
1377 * @param aType
1378 * @return
1379 */
1380std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
1381{
1382 std::list<VirtualSystemDescriptionEntry*> vsd;
1383
1384 list<VirtualSystemDescriptionEntry>::iterator it;
1385 for (it = m->llDescriptions.begin();
1386 it != m->llDescriptions.end();
1387 ++it)
1388 {
1389 if (it->type == aType)
1390 vsd.push_back(&(*it));
1391 }
1392
1393 return vsd;
1394}
1395
1396/**
1397 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1398 * the given reference ID. Useful when needing the controller for a particular
1399 * virtual disk.
1400 * @param id
1401 * @return
1402 */
1403const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
1404{
1405 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1406 list<VirtualSystemDescriptionEntry>::const_iterator it;
1407 for (it = m->llDescriptions.begin();
1408 it != m->llDescriptions.end();
1409 ++it)
1410 {
1411 const VirtualSystemDescriptionEntry &d = *it;
1412 switch (d.type)
1413 {
1414 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1415 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1416 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1417 case VirtualSystemDescriptionType_HardDiskControllerSAS:
1418 if (d.strRef == strRef)
1419 return &d;
1420 break;
1421 }
1422 }
1423
1424 return NULL;
1425}
1426
1427/**
1428 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1429 * contains a <vbox:Machine> element. This method then attempts to parse that and
1430 * create a MachineConfigFile instance from it which is stored in this instance data
1431 * and can then be used to create a machine.
1432 *
1433 * This must only be called once per instance.
1434 *
1435 * This rethrows all XML and logic errors from MachineConfigFile.
1436 *
1437 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1438 * DOM tree.
1439 */
1440void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmMachine)
1441{
1442 settings::MachineConfigFile *pConfig = NULL;
1443
1444 Assert(m->pConfig == NULL);
1445
1446 try
1447 {
1448 pConfig = new settings::MachineConfigFile(NULL);
1449 pConfig->importMachineXML(elmMachine);
1450
1451 m->pConfig = pConfig;
1452 }
1453 catch (...)
1454 {
1455 if (pConfig)
1456 delete pConfig;
1457 throw;
1458 }
1459}
1460
1461/**
1462 * Returns the machine config created by importVboxMachineXML() or NULL if there's none.
1463 * @return
1464 */
1465const settings::MachineConfigFile* VirtualSystemDescription::getMachineConfig() const
1466{
1467 return m->pConfig;
1468}
1469
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