VirtualBox

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

最後變更 在這個檔案從31676是 31676,由 vboxsync 提交於 15 年 前

Main/FE/Qt4: add initial OVA support

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette