VirtualBox

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

Last change on this file since 48607 was 48538, checked in by vboxsync, 12 years ago

Main/NetworkAdapter+Machine+Appliance+SystemProperties+Medium+Console+Settings+IDL: make NAT networking a separate network attachment type which improves the user experience, store the necessary settings, plus changing the design of the methods which will move images and entire VMs, they lacked a progress object
Frontends/VirtualBox: adapted fully, can configure NAT networks with proper drop down list support
Frontends/VBoxManage: also supports NAT networks completely, and adds the long missing code to list intnets

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

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