VirtualBox

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

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

Main: 64-bit unknown OS types.

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

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