VirtualBox

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

Last change on this file since 48311 was 47716, checked in by vboxsync, 11 years ago

pr6022. 3rd variant (using VFS streaming feature) of GZIP support for reading the gzipped storage images from OVA/OVF package has been added.

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