VirtualBox

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

Last change on this file since 59577 was 59577, checked in by vboxsync, 9 years ago

Main: Removed the VBOX_WITH_S3 code because we haven't maintained it properly for years.

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