VirtualBox

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

Last change on this file since 71963 was 70217, checked in by vboxsync, 7 years ago

VBox/ostypes.h,Main: Forced an NT 3.x type into the enum. NT 3.x needs floppy and have no use for USB.

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

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