VirtualBox

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

Last change on this file since 49047 was 49039, checked in by vboxsync, 11 years ago

IPRT: Filename extension versus suffix cleanup, long overdue.

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