VirtualBox

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

Last change on this file since 49911 was 49760, checked in by vboxsync, 11 years ago

6813 stage 2 rev 4

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

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