VirtualBox

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

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

Export/import OVA/OVF package supports ISO images. The problem with the wrong search files in the archive has been resolved. (see #5429). 2 new elements SASD and EPASD were added in the OVF XML file structure (see #6022).

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