VirtualBox

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

Last change on this file since 49716 was 49620, checked in by vboxsync, 11 years ago

pr7072. Search an appropriate medium format using, firstly, URL given in the OVF description file and, secondly, using an image extension.

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