VirtualBox

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

Last change on this file since 67954 was 67184, checked in by vboxsync, 7 years ago

Main: Reworking IAppliance export to use new TAR creator. Changes protected by VBOX_WITH_NEW_TAR_CREATOR define (currently not defined).

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