VirtualBox

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

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

corrected a progress information when there are CD/DVD images

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

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