VirtualBox

source: vbox/trunk/src/VBox/Main/ApplianceImpl.cpp@ 30676

Last change on this file since 30676 was 30676, checked in by vboxsync, 14 years ago

Main: back out r63429

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