VirtualBox

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

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

ApplianceImplExport.cpp: VBox is never ever written Vbox.

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