VirtualBox

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

Last change on this file since 41105 was 41105, checked in by vboxsync, 13 years ago

use openMedium instead of findMedium

  • 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 41105 2012-05-01 18:14:46Z vboxsync $ */
2/** @file
3 *
4 * IAppliance and IVirtualSystem COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2008-2011 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
629#if 0 // Substitute call to FindMedium to OpenMedium
630 while ( RTPathExists(tmpName)
631 || mVirtualBox->FindMedium(Bstr(tmpName).raw(), DeviceType_HardDisk, &harddisk) != VBOX_E_OBJECT_NOT_FOUND
632 )
633#endif
634
635 while ( RTPathExists(tmpName)
636 || mVirtualBox->OpenMedium(Bstr(tmpName).raw(),
637 DeviceType_HardDisk,
638 AccessMode_ReadWrite,
639 FALSE /* fForceNewUuid */,
640 &harddisk) != VBOX_E_OBJECT_NOT_FOUND
641 )
642 {
643 RTStrFree(tmpName);
644 char *tmpDir = RTStrDup(aName.c_str());
645 RTPathStripFilename(tmpDir);;
646 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
647 RTPathStripExt(tmpFile);
648 const char *tmpExt = RTPathExt(aName.c_str());
649 RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
650 RTStrFree(tmpFile);
651 RTStrFree(tmpDir);
652 ++i;
653 }
654 aName = tmpName;
655 RTStrFree(tmpName);
656
657 return S_OK;
658}
659
660/**
661 * Called from Appliance::importImpl() and Appliance::writeImpl() to set up a
662 * progress object with the proper weights and maximum progress values.
663 *
664 * @param pProgress
665 * @param bstrDescription
666 * @param mode
667 * @return
668 */
669HRESULT Appliance::setUpProgress(ComObjPtr<Progress> &pProgress,
670 const Bstr &bstrDescription,
671 SetUpProgressMode mode)
672{
673 HRESULT rc;
674
675 /* Create the progress object */
676 pProgress.createObject();
677
678 // compute the disks weight (this sets ulTotalDisksMB and cDisks in the instance data)
679 disksWeight();
680
681 m->ulWeightForManifestOperation = 0;
682
683 ULONG cOperations;
684 ULONG ulTotalOperationsWeight;
685
686 cOperations = 1 // one for XML setup
687 + m->cDisks; // plus one per disk
688 if (m->ulTotalDisksMB)
689 {
690 m->ulWeightForXmlOperation = (ULONG)((double)m->ulTotalDisksMB * 1 / 100); // use 1% of the progress for the XML
691 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
692 }
693 else
694 {
695 // no disks to export:
696 m->ulWeightForXmlOperation = 1;
697 ulTotalOperationsWeight = 1;
698 }
699
700 switch (mode)
701 {
702 case ImportFile:
703 {
704 break;
705 }
706 case WriteFile:
707 {
708 // assume that creating the manifest will take .1% of the time it takes to export the disks
709 if (m->fManifest)
710 {
711 ++cOperations; // another one for creating the manifest
712
713 m->ulWeightForManifestOperation = (ULONG)((double)m->ulTotalDisksMB * .1 / 100); // use .5% of the progress for the manifest
714 ulTotalOperationsWeight += m->ulWeightForManifestOperation;
715 }
716 break;
717 }
718 case ImportS3:
719 {
720 cOperations += 1 + 1; // another one for the manifest file & another one for the import
721 ulTotalOperationsWeight = m->ulTotalDisksMB;
722 if (!m->ulTotalDisksMB)
723 // no disks to export:
724 ulTotalOperationsWeight = 1;
725
726 ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import
727 ulTotalOperationsWeight += ulImportWeight;
728
729 m->ulWeightForXmlOperation = ulImportWeight; /* save for using later */
730
731 ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init
732 ulTotalOperationsWeight += ulInitWeight;
733 break;
734 }
735 case WriteS3:
736 {
737 cOperations += 1 + 1; // another one for the mf & another one for temporary creation
738
739 if (m->ulTotalDisksMB)
740 {
741 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)
742 ulTotalOperationsWeight = m->ulTotalDisksMB + m->ulWeightForXmlOperation;
743 }
744 else
745 {
746 // no disks to export:
747 ulTotalOperationsWeight = 1;
748 m->ulWeightForXmlOperation = 1;
749 }
750 ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
751 ulTotalOperationsWeight += ulOVFCreationWeight;
752 break;
753 }
754 }
755
756 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightForXmlOperation = %d\n",
757 m->ulTotalDisksMB, m->cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightForXmlOperation));
758
759 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
760 bstrDescription.raw(),
761 TRUE /* aCancelable */,
762 cOperations, // ULONG cOperations,
763 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
764 bstrDescription.raw(), // CBSTR bstrFirstOperationDescription,
765 m->ulWeightForXmlOperation); // ULONG ulFirstOperationWeight,
766 return rc;
767}
768
769/**
770 * Called from the import and export background threads to synchronize the second
771 * background disk thread's progress object with the current progress object so
772 * that the user interface sees progress correctly and that cancel signals are
773 * passed on to the second thread.
774 * @param pProgressThis Progress object of the current thread.
775 * @param pProgressAsync Progress object of asynchronous task running in background.
776 */
777void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
778 ComPtr<IProgress> &pProgressAsync)
779{
780 HRESULT rc;
781
782 // now loop until the asynchronous operation completes and then report its result
783 BOOL fCompleted;
784 BOOL fCanceled;
785 ULONG currentPercent;
786 ULONG cOp = 0;
787 while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
788 {
789 rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
790 if (FAILED(rc)) throw rc;
791 if (fCanceled)
792 pProgressAsync->Cancel();
793 /* Check if the current operation has changed. It is also possible
794 that in the meantime more than one async operation was finished. So
795 we have to loop as long as we reached the same operation count. */
796 ULONG curOp;
797 for(;;)
798 {
799 rc = pProgressAsync->COMGETTER(Operation(&curOp));
800 if (FAILED(rc)) throw rc;
801 if (cOp != curOp)
802 {
803 Bstr bstr;
804 ULONG currentWeight;
805 rc = pProgressAsync->COMGETTER(OperationDescription(bstr.asOutParam()));
806 if (FAILED(rc)) throw rc;
807 rc = pProgressAsync->COMGETTER(OperationWeight(&currentWeight));
808 if (FAILED(rc)) throw rc;
809 rc = pProgressThis->SetNextOperation(bstr.raw(), currentWeight);
810 if (FAILED(rc)) throw rc;
811 ++cOp;
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