VirtualBox

source: vbox/trunk/src/VBox/Main/ApplianceImpl.cpp@ 28098

Last change on this file since 28098 was 27918, checked in by vboxsync, 15 years ago

Main/OVF: import vbox:Machine XML within OVF, first batch (XML is parsed and machine config created, but COM Machine can't handle it yet)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.7 KB
Line 
1/* $Id: ApplianceImpl.cpp 27918 2010-03-31 17:10:40Z vboxsync $ */
2/** @file
3 *
4 * IAppliance and IVirtualSystem COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2008-2010 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include <iprt/path.h>
24
25#include <VBox/com/array.h>
26
27#include "ApplianceImpl.h"
28#include "VFSExplorerImpl.h"
29#include "VirtualBoxImpl.h"
30#include "GuestOSTypeImpl.h"
31#include "ProgressImpl.h"
32#include "MachineImpl.h"
33
34#include "AutoCaller.h"
35#include "Logging.h"
36
37#include "ApplianceImplPrivate.h"
38
39using namespace std;
40
41////////////////////////////////////////////////////////////////////////////////
42//
43// Internal helpers
44//
45////////////////////////////////////////////////////////////////////////////////
46
47static const struct
48{
49 ovf::CIMOSType_T cim;
50 const char *pcszVbox;
51}
52g_osTypes[] =
53{
54 { ovf::CIMOSType_CIMOS_Unknown, SchemaDefs_OSTypeId_Other },
55 { ovf::CIMOSType_CIMOS_OS2, SchemaDefs_OSTypeId_OS2 },
56 { ovf::CIMOSType_CIMOS_MSDOS, SchemaDefs_OSTypeId_DOS },
57 { ovf::CIMOSType_CIMOS_WIN3x, SchemaDefs_OSTypeId_Windows31 },
58 { ovf::CIMOSType_CIMOS_WIN95, SchemaDefs_OSTypeId_Windows95 },
59 { ovf::CIMOSType_CIMOS_WIN98, SchemaDefs_OSTypeId_Windows98 },
60 { ovf::CIMOSType_CIMOS_WINNT, SchemaDefs_OSTypeId_WindowsNT4 },
61 { ovf::CIMOSType_CIMOS_NetWare, SchemaDefs_OSTypeId_Netware },
62 { ovf::CIMOSType_CIMOS_NovellOES, SchemaDefs_OSTypeId_Netware },
63 { ovf::CIMOSType_CIMOS_Solaris, SchemaDefs_OSTypeId_OpenSolaris },
64 { ovf::CIMOSType_CIMOS_SunOS, SchemaDefs_OSTypeId_OpenSolaris },
65 { ovf::CIMOSType_CIMOS_FreeBSD, SchemaDefs_OSTypeId_FreeBSD },
66 { ovf::CIMOSType_CIMOS_NetBSD, SchemaDefs_OSTypeId_NetBSD },
67 { ovf::CIMOSType_CIMOS_QNX, SchemaDefs_OSTypeId_QNX },
68 { ovf::CIMOSType_CIMOS_Windows2000, SchemaDefs_OSTypeId_Windows2000 },
69 { ovf::CIMOSType_CIMOS_WindowsMe, SchemaDefs_OSTypeId_WindowsMe },
70 { ovf::CIMOSType_CIMOS_OpenBSD, SchemaDefs_OSTypeId_OpenBSD },
71 { ovf::CIMOSType_CIMOS_WindowsXP, SchemaDefs_OSTypeId_WindowsXP },
72 { ovf::CIMOSType_CIMOS_WindowsXPEmbedded, SchemaDefs_OSTypeId_WindowsXP },
73 { ovf::CIMOSType_CIMOS_WindowsEmbeddedforPointofService, SchemaDefs_OSTypeId_WindowsXP },
74 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003, SchemaDefs_OSTypeId_Windows2003 },
75 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2003_64, SchemaDefs_OSTypeId_Windows2003_64 },
76 { ovf::CIMOSType_CIMOS_WindowsXP_64, SchemaDefs_OSTypeId_WindowsXP_64 },
77 { ovf::CIMOSType_CIMOS_WindowsVista, SchemaDefs_OSTypeId_WindowsVista },
78 { ovf::CIMOSType_CIMOS_WindowsVista_64, SchemaDefs_OSTypeId_WindowsVista_64 },
79 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008, SchemaDefs_OSTypeId_Windows2008 },
80 { ovf::CIMOSType_CIMOS_MicrosoftWindowsServer2008_64, SchemaDefs_OSTypeId_Windows2008_64 },
81 { ovf::CIMOSType_CIMOS_FreeBSD_64, SchemaDefs_OSTypeId_FreeBSD_64 },
82 { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux, SchemaDefs_OSTypeId_RedHat },
83 { ovf::CIMOSType_CIMOS_RedHatEnterpriseLinux_64, SchemaDefs_OSTypeId_RedHat_64 },
84 { ovf::CIMOSType_CIMOS_Solaris_64, SchemaDefs_OSTypeId_OpenSolaris_64 },
85 { ovf::CIMOSType_CIMOS_SUSE, SchemaDefs_OSTypeId_OpenSUSE },
86 { ovf::CIMOSType_CIMOS_SLES, SchemaDefs_OSTypeId_OpenSUSE },
87 { ovf::CIMOSType_CIMOS_NovellLinuxDesktop, SchemaDefs_OSTypeId_OpenSUSE },
88 { ovf::CIMOSType_CIMOS_SUSE_64, SchemaDefs_OSTypeId_OpenSUSE_64 },
89 { ovf::CIMOSType_CIMOS_SLES_64, SchemaDefs_OSTypeId_OpenSUSE_64 },
90 { ovf::CIMOSType_CIMOS_LINUX, SchemaDefs_OSTypeId_Linux },
91 { ovf::CIMOSType_CIMOS_SunJavaDesktopSystem, SchemaDefs_OSTypeId_Linux },
92 { ovf::CIMOSType_CIMOS_TurboLinux, SchemaDefs_OSTypeId_Linux},
93
94 // { ovf::CIMOSType_CIMOS_TurboLinux_64, },
95
96 { ovf::CIMOSType_CIMOS_Mandriva, SchemaDefs_OSTypeId_Mandriva },
97 { ovf::CIMOSType_CIMOS_Mandriva_64, SchemaDefs_OSTypeId_Mandriva_64 },
98 { ovf::CIMOSType_CIMOS_Ubuntu, SchemaDefs_OSTypeId_Ubuntu },
99 { ovf::CIMOSType_CIMOS_Ubuntu_64, SchemaDefs_OSTypeId_Ubuntu_64 },
100 { ovf::CIMOSType_CIMOS_Debian, SchemaDefs_OSTypeId_Debian },
101 { ovf::CIMOSType_CIMOS_Debian_64, SchemaDefs_OSTypeId_Debian_64 },
102 { ovf::CIMOSType_CIMOS_Linux_2_4_x, SchemaDefs_OSTypeId_Linux24 },
103 { ovf::CIMOSType_CIMOS_Linux_2_4_x_64, SchemaDefs_OSTypeId_Linux24_64 },
104 { ovf::CIMOSType_CIMOS_Linux_2_6_x, SchemaDefs_OSTypeId_Linux26 },
105 { ovf::CIMOSType_CIMOS_Linux_2_6_x_64, SchemaDefs_OSTypeId_Linux26_64 },
106 { ovf::CIMOSType_CIMOS_Linux_64, SchemaDefs_OSTypeId_Linux26_64 }
107};
108
109/* Pattern structure for matching the OS type description field */
110struct osTypePattern
111{
112 const char *pcszPattern;
113 const char *pcszVbox;
114};
115
116/* These are the 32-Bit ones. They are sorted by priority. */
117static const osTypePattern g_osTypesPattern[] =
118{
119 {"Windows NT", SchemaDefs_OSTypeId_WindowsNT4},
120 {"Windows XP", SchemaDefs_OSTypeId_WindowsXP},
121 {"Windows 2000", SchemaDefs_OSTypeId_Windows2000},
122 {"Windows 2003", SchemaDefs_OSTypeId_Windows2003},
123 {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista},
124 {"Windows 2008", SchemaDefs_OSTypeId_Windows2008},
125 {"SUSE", SchemaDefs_OSTypeId_OpenSUSE},
126 {"Novell", SchemaDefs_OSTypeId_OpenSUSE},
127 {"Red Hat", SchemaDefs_OSTypeId_RedHat},
128 {"Mandriva", SchemaDefs_OSTypeId_Mandriva},
129 {"Ubuntu", SchemaDefs_OSTypeId_Ubuntu},
130 {"Debian", SchemaDefs_OSTypeId_Debian},
131 {"QNX", SchemaDefs_OSTypeId_QNX},
132 {"Linux 2.4", SchemaDefs_OSTypeId_Linux24},
133 {"Linux 2.6", SchemaDefs_OSTypeId_Linux26},
134 {"Linux", SchemaDefs_OSTypeId_Linux},
135 {"OpenSolaris", SchemaDefs_OSTypeId_OpenSolaris},
136 {"Solaris", SchemaDefs_OSTypeId_OpenSolaris},
137 {"FreeBSD", SchemaDefs_OSTypeId_FreeBSD},
138 {"NetBSD", SchemaDefs_OSTypeId_NetBSD},
139 {"Windows 95", SchemaDefs_OSTypeId_Windows95},
140 {"Windows 98", SchemaDefs_OSTypeId_Windows98},
141 {"Windows Me", SchemaDefs_OSTypeId_WindowsMe},
142 {"Windows 3.", SchemaDefs_OSTypeId_Windows31},
143 {"DOS", SchemaDefs_OSTypeId_DOS},
144 {"OS2", SchemaDefs_OSTypeId_OS2}
145};
146
147/* These are the 64-Bit ones. They are sorted by priority. */
148static const osTypePattern g_osTypesPattern64[] =
149{
150 {"Windows XP", SchemaDefs_OSTypeId_WindowsXP_64},
151 {"Windows 2003", SchemaDefs_OSTypeId_Windows2003_64},
152 {"Windows Vista", SchemaDefs_OSTypeId_WindowsVista_64},
153 {"Windows 2008", SchemaDefs_OSTypeId_Windows2008_64},
154 {"SUSE", SchemaDefs_OSTypeId_OpenSUSE_64},
155 {"Novell", SchemaDefs_OSTypeId_OpenSUSE_64},
156 {"Red Hat", SchemaDefs_OSTypeId_RedHat_64},
157 {"Mandriva", SchemaDefs_OSTypeId_Mandriva_64},
158 {"Ubuntu", SchemaDefs_OSTypeId_Ubuntu_64},
159 {"Debian", SchemaDefs_OSTypeId_Debian_64},
160 {"Linux 2.4", SchemaDefs_OSTypeId_Linux24_64},
161 {"Linux 2.6", SchemaDefs_OSTypeId_Linux26_64},
162 {"Linux", SchemaDefs_OSTypeId_Linux26_64},
163 {"OpenSolaris", SchemaDefs_OSTypeId_OpenSolaris_64},
164 {"Solaris", SchemaDefs_OSTypeId_OpenSolaris_64},
165 {"FreeBSD", SchemaDefs_OSTypeId_FreeBSD_64},
166};
167
168/**
169 * Private helper func that suggests a VirtualBox guest OS type
170 * for the given OVF operating system type.
171 * @param osTypeVBox
172 * @param c
173 * @param cStr
174 */
175void convertCIMOSType2VBoxOSType(Utf8Str &strType, ovf::CIMOSType_T c, const Utf8Str &cStr)
176{
177 /* First check if the type is other/other_64 */
178 if (c == ovf::CIMOSType_CIMOS_Other)
179 {
180 for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern); ++i)
181 if (cStr.contains (g_osTypesPattern[i].pcszPattern, Utf8Str::CaseInsensitive))
182 {
183 strType = g_osTypesPattern[i].pcszVbox;
184 return;
185 }
186 }
187 else if (c == ovf::CIMOSType_CIMOS_Other_64)
188 {
189 for (size_t i=0; i < RT_ELEMENTS(g_osTypesPattern64); ++i)
190 if (cStr.contains (g_osTypesPattern64[i].pcszPattern, Utf8Str::CaseInsensitive))
191 {
192 strType = g_osTypesPattern64[i].pcszVbox;
193 return;
194 }
195 }
196
197 for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
198 {
199 if (c == g_osTypes[i].cim)
200 {
201 strType = g_osTypes[i].pcszVbox;
202 return;
203 }
204 }
205
206 strType = SchemaDefs_OSTypeId_Other;
207}
208
209/**
210 * Private helper func that suggests a VirtualBox guest OS type
211 * for the given OVF operating system type.
212 * @param osTypeVBox
213 * @param c
214 */
215ovf::CIMOSType_T convertVBoxOSType2CIMOSType(const char *pcszVbox)
216{
217 for (size_t i = 0; i < RT_ELEMENTS(g_osTypes); ++i)
218 {
219 if (!RTStrICmp(pcszVbox, g_osTypes[i].pcszVbox))
220 return g_osTypes[i].cim;
221 }
222
223 return ovf::CIMOSType_CIMOS_Other;
224}
225
226////////////////////////////////////////////////////////////////////////////////
227//
228// IVirtualBox public methods
229//
230////////////////////////////////////////////////////////////////////////////////
231
232// This code is here so we won't have to include the appliance headers in the
233// IVirtualBox implementation.
234
235/**
236 * Implementation for IVirtualBox::createAppliance.
237 *
238 * @param anAppliance IAppliance object created if S_OK is returned.
239 * @return S_OK or error.
240 */
241STDMETHODIMP VirtualBox::CreateAppliance(IAppliance** anAppliance)
242{
243 HRESULT rc;
244
245 ComObjPtr<Appliance> appliance;
246 appliance.createObject();
247 rc = appliance->init(this);
248
249 if (SUCCEEDED(rc))
250 appliance.queryInterfaceTo(anAppliance);
251
252 return rc;
253}
254
255////////////////////////////////////////////////////////////////////////////////
256//
257// Appliance constructor / destructor
258//
259////////////////////////////////////////////////////////////////////////////////
260
261Appliance::Appliance()
262 : mVirtualBox(NULL)
263{
264}
265
266Appliance::~Appliance()
267{
268}
269
270/**
271 * Appliance COM initializer.
272 * @param
273 * @return
274 */
275HRESULT Appliance::init(VirtualBox *aVirtualBox)
276{
277 /* Enclose the state transition NotReady->InInit->Ready */
278 AutoInitSpan autoInitSpan(this);
279 AssertReturn(autoInitSpan.isOk(), E_FAIL);
280
281 /* Weak reference to a VirtualBox object */
282 unconst(mVirtualBox) = aVirtualBox;
283
284 // initialize data
285 m = new Data;
286
287 /* Confirm a successful initialization */
288 autoInitSpan.setSucceeded();
289
290 return S_OK;
291}
292
293/**
294 * Appliance COM uninitializer.
295 * @return
296 */
297void Appliance::uninit()
298{
299 /* Enclose the state transition Ready->InUninit->NotReady */
300 AutoUninitSpan autoUninitSpan(this);
301 if (autoUninitSpan.uninitDone())
302 return;
303
304 delete m;
305 m = NULL;
306}
307
308////////////////////////////////////////////////////////////////////////////////
309//
310// IAppliance public methods
311//
312////////////////////////////////////////////////////////////////////////////////
313
314/**
315 * Public method implementation.
316 * @param
317 * @return
318 */
319STDMETHODIMP Appliance::COMGETTER(Path)(BSTR *aPath)
320{
321 if (!aPath)
322 return E_POINTER;
323
324 AutoCaller autoCaller(this);
325 if (FAILED(autoCaller.rc())) return autoCaller.rc();
326
327 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
328
329 if (!isApplianceIdle())
330 return E_ACCESSDENIED;
331
332 Bstr bstrPath(m->locInfo.strPath);
333 bstrPath.cloneTo(aPath);
334
335 return S_OK;
336}
337
338/**
339 * Public method implementation.
340 * @param
341 * @return
342 */
343STDMETHODIMP Appliance::COMGETTER(Disks)(ComSafeArrayOut(BSTR, aDisks))
344{
345 CheckComArgOutSafeArrayPointerValid(aDisks);
346
347 AutoCaller autoCaller(this);
348 if (FAILED(autoCaller.rc())) return autoCaller.rc();
349
350 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
351
352 if (!isApplianceIdle())
353 return E_ACCESSDENIED;
354
355 if (m->pReader) // OVFReader instantiated?
356 {
357 size_t c = m->pReader->m_mapDisks.size();
358 com::SafeArray<BSTR> sfaDisks(c);
359
360 ovf::DiskImagesMap::const_iterator it;
361 size_t i = 0;
362 for (it = m->pReader->m_mapDisks.begin();
363 it != m->pReader->m_mapDisks.end();
364 ++it, ++i)
365 {
366 // create a string representing this disk
367 const ovf::DiskImage &d = it->second;
368 char *psz = NULL;
369 RTStrAPrintf(&psz,
370 "%s\t"
371 "%RI64\t"
372 "%RI64\t"
373 "%s\t"
374 "%s\t"
375 "%RI64\t"
376 "%RI64\t"
377 "%s",
378 d.strDiskId.c_str(),
379 d.iCapacity,
380 d.iPopulatedSize,
381 d.strFormat.c_str(),
382 d.strHref.c_str(),
383 d.iSize,
384 d.iChunkSize,
385 d.strCompression.c_str());
386 Utf8Str utf(psz);
387 Bstr bstr(utf);
388 // push to safearray
389 bstr.cloneTo(&sfaDisks[i]);
390 RTStrFree(psz);
391 }
392
393 sfaDisks.detachTo(ComSafeArrayOutArg(aDisks));
394 }
395
396 return S_OK;
397}
398
399/**
400 * Public method implementation.
401 * @param
402 * @return
403 */
404STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
405{
406 CheckComArgOutSafeArrayPointerValid(aVirtualSystemDescriptions);
407
408 AutoCaller autoCaller(this);
409 if (FAILED(autoCaller.rc())) return autoCaller.rc();
410
411 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
412
413 if (!isApplianceIdle())
414 return E_ACCESSDENIED;
415
416 SafeIfaceArray<IVirtualSystemDescription> sfaVSD(m->virtualSystemDescriptions);
417 sfaVSD.detachTo(ComSafeArrayOutArg(aVirtualSystemDescriptions));
418
419 return S_OK;
420}
421
422STDMETHODIMP Appliance::CreateVFSExplorer(IN_BSTR aURI, IVFSExplorer **aExplorer)
423{
424 CheckComArgOutPointerValid(aExplorer);
425
426 AutoCaller autoCaller(this);
427 if (FAILED(autoCaller.rc())) return autoCaller.rc();
428
429 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
430
431 ComObjPtr<VFSExplorer> explorer;
432 HRESULT rc = S_OK;
433 try
434 {
435 Utf8Str uri(aURI);
436 /* Check which kind of export the user has requested */
437 LocationInfo li;
438 parseURI(uri, li);
439 /* Create the explorer object */
440 explorer.createObject();
441 rc = explorer->init(li.storageType, li.strPath, li.strHostname, li.strUsername, li.strPassword, mVirtualBox);
442 }
443 catch (HRESULT aRC)
444 {
445 rc = aRC;
446 }
447
448 if (SUCCEEDED(rc))
449 /* Return explorer to the caller */
450 explorer.queryInterfaceTo(aExplorer);
451
452 return rc;
453}
454
455/**
456* Public method implementation.
457 * @return
458 */
459STDMETHODIMP Appliance::GetWarnings(ComSafeArrayOut(BSTR, aWarnings))
460{
461 if (ComSafeArrayOutIsNull(aWarnings))
462 return E_POINTER;
463
464 AutoCaller autoCaller(this);
465 if (FAILED(autoCaller.rc())) return autoCaller.rc();
466
467 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
468
469 com::SafeArray<BSTR> sfaWarnings(m->llWarnings.size());
470
471 list<Utf8Str>::const_iterator it;
472 size_t i = 0;
473 for (it = m->llWarnings.begin();
474 it != m->llWarnings.end();
475 ++it, ++i)
476 {
477 Bstr bstr = *it;
478 bstr.cloneTo(&sfaWarnings[i]);
479 }
480
481 sfaWarnings.detachTo(ComSafeArrayOutArg(aWarnings));
482
483 return S_OK;
484}
485
486////////////////////////////////////////////////////////////////////////////////
487//
488// Appliance private methods
489//
490////////////////////////////////////////////////////////////////////////////////
491
492/**
493 * Returns true if the appliance is in "idle" state. This should always be the
494 * case unless an import or export is currently in progress. Similar to machine
495 * states, this permits the Appliance implementation code to let go of the
496 * Appliance object lock while a time-consuming disk conversion is in progress
497 * without exposing the appliance to conflicting calls.
498 *
499 * This sets an error on "this" (the appliance) and returns false if the appliance
500 * is busy. The caller should then return E_ACCESSDENIED.
501 *
502 * Must be called from under the object lock!
503 *
504 * @return
505 */
506bool Appliance::isApplianceIdle() const
507{
508 if (m->state == Data::ApplianceImporting)
509 setError(VBOX_E_INVALID_OBJECT_STATE, "The appliance is busy importing files");
510 else if (m->state == Data::ApplianceExporting)
511 setError(VBOX_E_INVALID_OBJECT_STATE, "The appliance is busy exporting files");
512 else
513 return true;
514
515 return false;
516}
517
518HRESULT Appliance::searchUniqueVMName(Utf8Str& aName) const
519{
520 IMachine *machine = NULL;
521 char *tmpName = RTStrDup(aName.c_str());
522 int i = 1;
523 /* @todo: Maybe too cost-intensive; try to find a lighter way */
524 while (mVirtualBox->FindMachine(Bstr(tmpName), &machine) != VBOX_E_OBJECT_NOT_FOUND)
525 {
526 RTStrFree(tmpName);
527 RTStrAPrintf(&tmpName, "%s_%d", aName.c_str(), i);
528 ++i;
529 }
530 aName = tmpName;
531 RTStrFree(tmpName);
532
533 return S_OK;
534}
535
536HRESULT Appliance::searchUniqueDiskImageFilePath(Utf8Str& aName) const
537{
538 IMedium *harddisk = NULL;
539 char *tmpName = RTStrDup(aName.c_str());
540 int i = 1;
541 /* Check if the file exists or if a file with this path is registered
542 * already */
543 /* @todo: Maybe too cost-intensive; try to find a lighter way */
544 while ( RTPathExists(tmpName)
545 || mVirtualBox->FindHardDisk(Bstr(tmpName), &harddisk) != VBOX_E_OBJECT_NOT_FOUND
546 )
547 {
548 RTStrFree(tmpName);
549 char *tmpDir = RTStrDup(aName.c_str());
550 RTPathStripFilename(tmpDir);;
551 char *tmpFile = RTStrDup(RTPathFilename(aName.c_str()));
552 RTPathStripExt(tmpFile);
553 const char *tmpExt = RTPathExt(aName.c_str());
554 RTStrAPrintf(&tmpName, "%s%c%s_%d%s", tmpDir, RTPATH_DELIMITER, tmpFile, i, tmpExt);
555 RTStrFree(tmpFile);
556 RTStrFree(tmpDir);
557 ++i;
558 }
559 aName = tmpName;
560 RTStrFree(tmpName);
561
562 return S_OK;
563}
564
565/**
566 * Called from the import and export background threads to synchronize the second
567 * background disk thread's progress object with the current progress object so
568 * that the user interface sees progress correctly and that cancel signals are
569 * passed on to the second thread.
570 * @param pProgressThis Progress object of the current thread.
571 * @param pProgressAsync Progress object of asynchronous task running in background.
572 */
573void Appliance::waitForAsyncProgress(ComObjPtr<Progress> &pProgressThis,
574 ComPtr<IProgress> &pProgressAsync)
575{
576 HRESULT rc;
577
578 // now loop until the asynchronous operation completes and then report its result
579 BOOL fCompleted;
580 BOOL fCanceled;
581 ULONG currentPercent;
582 while (SUCCEEDED(pProgressAsync->COMGETTER(Completed(&fCompleted))))
583 {
584 rc = pProgressThis->COMGETTER(Canceled)(&fCanceled);
585 if (FAILED(rc)) throw rc;
586 if (fCanceled)
587 {
588 pProgressAsync->Cancel();
589 break;
590 }
591
592 rc = pProgressAsync->COMGETTER(Percent(&currentPercent));
593 if (FAILED(rc)) throw rc;
594 if (!pProgressThis.isNull())
595 pProgressThis->SetCurrentOperationProgress(currentPercent);
596 if (fCompleted)
597 break;
598
599 /* Make sure the loop is not too tight */
600 rc = pProgressAsync->WaitForCompletion(100);
601 if (FAILED(rc)) throw rc;
602 }
603 // report result of asynchronous operation
604 LONG iRc;
605 rc = pProgressAsync->COMGETTER(ResultCode)(&iRc);
606 if (FAILED(rc)) throw rc;
607
608
609 // if the thread of the progress object has an error, then
610 // retrieve the error info from there, or it'll be lost
611 if (FAILED(iRc))
612 {
613 ProgressErrorInfo info(pProgressAsync);
614 Utf8Str str(info.getText());
615 const char *pcsz = str.c_str();
616 HRESULT rc2 = setError(iRc, pcsz);
617 throw rc2;
618 }
619}
620
621void Appliance::addWarning(const char* aWarning, ...)
622{
623 va_list args;
624 va_start(args, aWarning);
625 Utf8StrFmtVA str(aWarning, args);
626 va_end(args);
627 m->llWarnings.push_back(str);
628}
629
630void Appliance::disksWeight(uint32_t &ulTotalMB, uint32_t &cDisks) const
631{
632 ulTotalMB = 0;
633 cDisks = 0;
634 /* Weigh the disk images according to their sizes */
635 list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
636 for (it = m->virtualSystemDescriptions.begin();
637 it != m->virtualSystemDescriptions.end();
638 ++it)
639 {
640 ComObjPtr<VirtualSystemDescription> vsdescThis = (*it);
641 /* One for every hard disk of the Virtual System */
642 std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
643 std::list<VirtualSystemDescriptionEntry*>::const_iterator itH;
644 for (itH = avsdeHDs.begin();
645 itH != avsdeHDs.end();
646 ++itH)
647 {
648 const VirtualSystemDescriptionEntry *pHD = *itH;
649 ulTotalMB += pHD->ulSizeMB;
650 ++cDisks;
651 }
652 }
653
654}
655
656HRESULT Appliance::setUpProgressFS(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
657{
658 HRESULT rc;
659
660 /* Create the progress object */
661 pProgress.createObject();
662
663 /* Weigh the disk images according to their sizes */
664 uint32_t ulTotalMB;
665 uint32_t cDisks;
666 disksWeight(ulTotalMB, cDisks);
667
668 ULONG cOperations = 1 + cDisks; // one op per disk plus 1 for the XML
669
670 ULONG ulTotalOperationsWeight;
671 if (ulTotalMB)
672 {
673 m->ulWeightPerOperation = (ULONG)((double)ulTotalMB * 1 / 100); // use 1% of the progress for the XML
674 ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
675 }
676 else
677 {
678 // no disks to export:
679 ulTotalOperationsWeight = 1;
680 m->ulWeightPerOperation = 1;
681 }
682
683 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
684 ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
685
686 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
687 bstrDescription,
688 TRUE /* aCancelable */,
689 cOperations, // ULONG cOperations,
690 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
691 bstrDescription, // CBSTR bstrFirstOperationDescription,
692 m->ulWeightPerOperation); // ULONG ulFirstOperationWeight,
693 return rc;
694}
695
696HRESULT Appliance::setUpProgressImportS3(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
697{
698 HRESULT rc;
699
700 /* Create the progress object */
701 pProgress.createObject();
702
703 /* Weigh the disk images according to their sizes */
704 uint32_t ulTotalMB;
705 uint32_t cDisks;
706 disksWeight(ulTotalMB, cDisks);
707
708 ULONG cOperations = 1 + 1 + 1 + cDisks; // one op per disk plus 1 for init, plus 1 for the manifest file & 1 plus for the import */
709
710 ULONG ulTotalOperationsWeight = ulTotalMB;
711 if (!ulTotalOperationsWeight)
712 // no disks to export:
713 ulTotalOperationsWeight = 1;
714
715 ULONG ulImportWeight = (ULONG)((double)ulTotalOperationsWeight * 50 / 100); // use 50% for import
716 ulTotalOperationsWeight += ulImportWeight;
717
718 m->ulWeightPerOperation = ulImportWeight; /* save for using later */
719
720 ULONG ulInitWeight = (ULONG)((double)ulTotalOperationsWeight * 0.1 / 100); // use 0.1% for init
721 ulTotalOperationsWeight += ulInitWeight;
722
723 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
724 ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
725
726 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
727 bstrDescription,
728 TRUE /* aCancelable */,
729 cOperations, // ULONG cOperations,
730 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
731 Bstr(tr("Init")), // CBSTR bstrFirstOperationDescription,
732 ulInitWeight); // ULONG ulFirstOperationWeight,
733 return rc;
734}
735
736HRESULT Appliance::setUpProgressWriteS3(ComObjPtr<Progress> &pProgress, const Bstr &bstrDescription)
737{
738 HRESULT rc;
739
740 /* Create the progress object */
741 pProgress.createObject();
742
743 /* Weigh the disk images according to their sizes */
744 uint32_t ulTotalMB;
745 uint32_t cDisks;
746 disksWeight(ulTotalMB, cDisks);
747
748 ULONG cOperations = 1 + 1 + 1 + cDisks; // one op per disk plus 1 for the OVF, plus 1 for the mf & 1 plus to the temporary creation */
749
750 ULONG ulTotalOperationsWeight;
751 if (ulTotalMB)
752 {
753 m->ulWeightPerOperation = (ULONG)((double)ulTotalMB * 1 / 100); // use 1% of the progress for OVF file upload (we didn't know the size at this point)
754 ulTotalOperationsWeight = ulTotalMB + m->ulWeightPerOperation;
755 }
756 else
757 {
758 // no disks to export:
759 ulTotalOperationsWeight = 1;
760 m->ulWeightPerOperation = 1;
761 }
762 ULONG ulOVFCreationWeight = (ULONG)((double)ulTotalOperationsWeight * 50.0 / 100.0); /* Use 50% for the creation of the OVF & the disks */
763 ulTotalOperationsWeight += ulOVFCreationWeight;
764
765 Log(("Setting up progress object: ulTotalMB = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
766 ulTotalMB, cDisks, cOperations, ulTotalOperationsWeight, m->ulWeightPerOperation));
767
768 rc = pProgress->init(mVirtualBox, static_cast<IAppliance*>(this),
769 bstrDescription,
770 TRUE /* aCancelable */,
771 cOperations, // ULONG cOperations,
772 ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
773 bstrDescription, // CBSTR bstrFirstOperationDescription,
774 ulOVFCreationWeight); // ULONG ulFirstOperationWeight,
775 return rc;
776}
777
778void Appliance::parseURI(Utf8Str strUri, LocationInfo &locInfo) const
779{
780 /* Check the URI for the protocol */
781 if (strUri.startsWith("file://", Utf8Str::CaseInsensitive)) /* File based */
782 {
783 locInfo.storageType = VFSType_File;
784 strUri = strUri.substr(sizeof("file://") - 1);
785 }
786 else if (strUri.startsWith("SunCloud://", Utf8Str::CaseInsensitive)) /* Sun Cloud service */
787 {
788 locInfo.storageType = VFSType_S3;
789 strUri = strUri.substr(sizeof("SunCloud://") - 1);
790 }
791 else if (strUri.startsWith("S3://", Utf8Str::CaseInsensitive)) /* S3 service */
792 {
793 locInfo.storageType = VFSType_S3;
794 strUri = strUri.substr(sizeof("S3://") - 1);
795 }
796 else if (strUri.startsWith("webdav://", Utf8Str::CaseInsensitive)) /* webdav service */
797 throw E_NOTIMPL;
798
799 /* Not necessary on a file based URI */
800 if (locInfo.storageType != VFSType_File)
801 {
802 size_t uppos = strUri.find("@"); /* username:password combo */
803 if (uppos != Utf8Str::npos)
804 {
805 locInfo.strUsername = strUri.substr(0, uppos);
806 strUri = strUri.substr(uppos + 1);
807 size_t upos = locInfo.strUsername.find(":");
808 if (upos != Utf8Str::npos)
809 {
810 locInfo.strPassword = locInfo.strUsername.substr(upos + 1);
811 locInfo.strUsername = locInfo.strUsername.substr(0, upos);
812 }
813 }
814 size_t hpos = strUri.find("/"); /* hostname part */
815 if (hpos != Utf8Str::npos)
816 {
817 locInfo.strHostname = strUri.substr(0, hpos);
818 strUri = strUri.substr(hpos);
819 }
820 }
821
822 locInfo.strPath = strUri;
823}
824
825void Appliance::parseBucket(Utf8Str &aPath, Utf8Str &aBucket) const
826{
827 /* Buckets are S3 specific. So parse the bucket out of the file path */
828 if (!aPath.startsWith("/"))
829 throw setError(E_INVALIDARG,
830 tr("The path '%s' must start with /"), aPath.c_str());
831 size_t bpos = aPath.find("/", 1);
832 if (bpos != Utf8Str::npos)
833 {
834 aBucket = aPath.substr(1, bpos - 1); /* The bucket without any slashes */
835 aPath = aPath.substr(bpos); /* The rest of the file path */
836 }
837 /* If there is no bucket name provided reject it */
838 if (aBucket.isEmpty())
839 throw setError(E_INVALIDARG,
840 tr("You doesn't provide a bucket name in the URI '%s'"), aPath.c_str());
841}
842
843Utf8Str Appliance::manifestFileName(Utf8Str aPath) const
844{
845 /* Get the name part */
846 char *pszMfName = RTStrDup(RTPathFilename(aPath.c_str()));
847 /* Strip any extensions */
848 RTPathStripExt(pszMfName);
849 /* Path without the filename */
850 aPath.stripFilename();
851 /* Format the manifest path */
852 Utf8StrFmt strMfFile("%s/%s.mf", aPath.c_str(), pszMfName);
853 RTStrFree(pszMfName);
854 return strMfFile;
855}
856
857/**
858 *
859 * @return
860 */
861int Appliance::TaskOVF::startThread()
862{
863 int vrc = RTThreadCreate(NULL, Appliance::taskThreadImportOrExport, this,
864 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
865 "Appliance::Task");
866
867 ComAssertMsgRCRet(vrc,
868 ("Could not create OVF task thread (%Rrc)\n", vrc), E_FAIL);
869
870 return S_OK;
871}
872
873/**
874 * Thread function for the thread started in Appliance::readImpl() and Appliance::importImpl()
875 * and Appliance::writeImpl().
876 * This will in turn call Appliance::readFS() or Appliance::readS3() or Appliance::importFS()
877 * or Appliance::importS3() or Appliance::writeFS() or Appliance::writeS3().
878 *
879 * @param aThread
880 * @param pvUser
881 */
882/* static */
883DECLCALLBACK(int) Appliance::taskThreadImportOrExport(RTTHREAD /* aThread */, void *pvUser)
884{
885 std::auto_ptr<TaskOVF> task(static_cast<TaskOVF*>(pvUser));
886 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
887
888 Appliance *pAppliance = task->pAppliance;
889
890 LogFlowFuncEnter();
891 LogFlowFunc(("Appliance %p\n", pAppliance));
892
893 HRESULT taskrc = S_OK;
894
895 switch (task->taskType)
896 {
897 case TaskOVF::Read:
898 if (task->locInfo.storageType == VFSType_File)
899 taskrc = pAppliance->readFS(task->locInfo);
900 else if (task->locInfo.storageType == VFSType_S3)
901 taskrc = pAppliance->readS3(task.get());
902 break;
903
904 case TaskOVF::Import:
905 if (task->locInfo.storageType == VFSType_File)
906 taskrc = pAppliance->importFS(task->locInfo, task->pProgress);
907 else if (task->locInfo.storageType == VFSType_S3)
908 taskrc = pAppliance->importS3(task.get());
909 break;
910
911 case TaskOVF::Write:
912 if (task->locInfo.storageType == VFSType_File)
913 taskrc = pAppliance->writeFS(task->locInfo, task->enFormat, task->pProgress);
914 else if (task->locInfo.storageType == VFSType_S3)
915 taskrc = pAppliance->writeS3(task.get());
916 break;
917 }
918
919 task->rc = taskrc;
920
921 if (!task->pProgress.isNull())
922 task->pProgress->notifyComplete(taskrc);
923
924 LogFlowFuncLeave();
925
926 return VINF_SUCCESS;
927}
928
929/* static */
930int Appliance::TaskOVF::updateProgress(unsigned uPercent, void *pvUser)
931{
932 Appliance::TaskOVF* pTask = *(Appliance::TaskOVF**)pvUser;
933
934 if ( pTask
935 && !pTask->pProgress.isNull())
936 {
937 BOOL fCanceled;
938 pTask->pProgress->COMGETTER(Canceled)(&fCanceled);
939 if (fCanceled)
940 return -1;
941 pTask->pProgress->SetCurrentOperationProgress(uPercent);
942 }
943 return VINF_SUCCESS;
944}
945
946////////////////////////////////////////////////////////////////////////////////
947//
948// IVirtualSystemDescription constructor / destructor
949//
950////////////////////////////////////////////////////////////////////////////////
951
952DEFINE_EMPTY_CTOR_DTOR(VirtualSystemDescription)
953
954/**
955 * COM initializer.
956 * @return
957 */
958HRESULT VirtualSystemDescription::init()
959{
960 /* Enclose the state transition NotReady->InInit->Ready */
961 AutoInitSpan autoInitSpan(this);
962 AssertReturn(autoInitSpan.isOk(), E_FAIL);
963
964 /* Initialize data */
965 m = new Data();
966 m->pConfig = NULL;
967
968 /* Confirm a successful initialization */
969 autoInitSpan.setSucceeded();
970 return S_OK;
971}
972
973/**
974* COM uninitializer.
975*/
976
977void VirtualSystemDescription::uninit()
978{
979 if (m->pConfig)
980 delete m->pConfig;
981 delete m;
982 m = NULL;
983}
984
985////////////////////////////////////////////////////////////////////////////////
986//
987// IVirtualSystemDescription public methods
988//
989////////////////////////////////////////////////////////////////////////////////
990
991/**
992 * Public method implementation.
993 * @param
994 * @return
995 */
996STDMETHODIMP VirtualSystemDescription::COMGETTER(Count)(ULONG *aCount)
997{
998 if (!aCount)
999 return E_POINTER;
1000
1001 AutoCaller autoCaller(this);
1002 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1003
1004 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1005
1006 *aCount = (ULONG)m->llDescriptions.size();
1007
1008 return S_OK;
1009}
1010
1011/**
1012 * Public method implementation.
1013 * @return
1014 */
1015STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1016 ComSafeArrayOut(BSTR, aRefs),
1017 ComSafeArrayOut(BSTR, aOrigValues),
1018 ComSafeArrayOut(BSTR, aVboxValues),
1019 ComSafeArrayOut(BSTR, aExtraConfigValues))
1020{
1021 if (ComSafeArrayOutIsNull(aTypes) ||
1022 ComSafeArrayOutIsNull(aRefs) ||
1023 ComSafeArrayOutIsNull(aOrigValues) ||
1024 ComSafeArrayOutIsNull(aVboxValues) ||
1025 ComSafeArrayOutIsNull(aExtraConfigValues))
1026 return E_POINTER;
1027
1028 AutoCaller autoCaller(this);
1029 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1030
1031 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1032
1033 ULONG c = (ULONG)m->llDescriptions.size();
1034 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1035 com::SafeArray<BSTR> sfaRefs(c);
1036 com::SafeArray<BSTR> sfaOrigValues(c);
1037 com::SafeArray<BSTR> sfaVboxValues(c);
1038 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1039
1040 list<VirtualSystemDescriptionEntry>::const_iterator it;
1041 size_t i = 0;
1042 for (it = m->llDescriptions.begin();
1043 it != m->llDescriptions.end();
1044 ++it, ++i)
1045 {
1046 const VirtualSystemDescriptionEntry &vsde = (*it);
1047
1048 sfaTypes[i] = vsde.type;
1049
1050 Bstr bstr = vsde.strRef;
1051 bstr.cloneTo(&sfaRefs[i]);
1052
1053 bstr = vsde.strOvf;
1054 bstr.cloneTo(&sfaOrigValues[i]);
1055
1056 bstr = vsde.strVbox;
1057 bstr.cloneTo(&sfaVboxValues[i]);
1058
1059 bstr = vsde.strExtraConfig;
1060 bstr.cloneTo(&sfaExtraConfigValues[i]);
1061 }
1062
1063 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1064 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1065 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1066 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1067 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1068
1069 return S_OK;
1070}
1071
1072/**
1073 * Public method implementation.
1074 * @return
1075 */
1076STDMETHODIMP VirtualSystemDescription::GetDescriptionByType(VirtualSystemDescriptionType_T aType,
1077 ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
1078 ComSafeArrayOut(BSTR, aRefs),
1079 ComSafeArrayOut(BSTR, aOrigValues),
1080 ComSafeArrayOut(BSTR, aVboxValues),
1081 ComSafeArrayOut(BSTR, aExtraConfigValues))
1082{
1083 if (ComSafeArrayOutIsNull(aTypes) ||
1084 ComSafeArrayOutIsNull(aRefs) ||
1085 ComSafeArrayOutIsNull(aOrigValues) ||
1086 ComSafeArrayOutIsNull(aVboxValues) ||
1087 ComSafeArrayOutIsNull(aExtraConfigValues))
1088 return E_POINTER;
1089
1090 AutoCaller autoCaller(this);
1091 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1092
1093 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1094
1095 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1096 ULONG c = (ULONG)vsd.size();
1097 com::SafeArray<VirtualSystemDescriptionType_T> sfaTypes(c);
1098 com::SafeArray<BSTR> sfaRefs(c);
1099 com::SafeArray<BSTR> sfaOrigValues(c);
1100 com::SafeArray<BSTR> sfaVboxValues(c);
1101 com::SafeArray<BSTR> sfaExtraConfigValues(c);
1102
1103 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1104 size_t i = 0;
1105 for (it = vsd.begin();
1106 it != vsd.end();
1107 ++it, ++i)
1108 {
1109 const VirtualSystemDescriptionEntry *vsde = (*it);
1110
1111 sfaTypes[i] = vsde->type;
1112
1113 Bstr bstr = vsde->strRef;
1114 bstr.cloneTo(&sfaRefs[i]);
1115
1116 bstr = vsde->strOvf;
1117 bstr.cloneTo(&sfaOrigValues[i]);
1118
1119 bstr = vsde->strVbox;
1120 bstr.cloneTo(&sfaVboxValues[i]);
1121
1122 bstr = vsde->strExtraConfig;
1123 bstr.cloneTo(&sfaExtraConfigValues[i]);
1124 }
1125
1126 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
1127 sfaRefs.detachTo(ComSafeArrayOutArg(aRefs));
1128 sfaOrigValues.detachTo(ComSafeArrayOutArg(aOrigValues));
1129 sfaVboxValues.detachTo(ComSafeArrayOutArg(aVboxValues));
1130 sfaExtraConfigValues.detachTo(ComSafeArrayOutArg(aExtraConfigValues));
1131
1132 return S_OK;
1133}
1134
1135/**
1136 * Public method implementation.
1137 * @return
1138 */
1139STDMETHODIMP VirtualSystemDescription::GetValuesByType(VirtualSystemDescriptionType_T aType,
1140 VirtualSystemDescriptionValueType_T aWhich,
1141 ComSafeArrayOut(BSTR, aValues))
1142{
1143 if (ComSafeArrayOutIsNull(aValues))
1144 return E_POINTER;
1145
1146 AutoCaller autoCaller(this);
1147 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1148
1149 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1150
1151 std::list<VirtualSystemDescriptionEntry*> vsd = findByType (aType);
1152 com::SafeArray<BSTR> sfaValues((ULONG)vsd.size());
1153
1154 list<VirtualSystemDescriptionEntry*>::const_iterator it;
1155 size_t i = 0;
1156 for (it = vsd.begin();
1157 it != vsd.end();
1158 ++it, ++i)
1159 {
1160 const VirtualSystemDescriptionEntry *vsde = (*it);
1161
1162 Bstr bstr;
1163 switch (aWhich)
1164 {
1165 case VirtualSystemDescriptionValueType_Reference: bstr = vsde->strRef; break;
1166 case VirtualSystemDescriptionValueType_Original: bstr = vsde->strOvf; break;
1167 case VirtualSystemDescriptionValueType_Auto: bstr = vsde->strVbox; break;
1168 case VirtualSystemDescriptionValueType_ExtraConfig: bstr = vsde->strExtraConfig; break;
1169 }
1170
1171 bstr.cloneTo(&sfaValues[i]);
1172 }
1173
1174 sfaValues.detachTo(ComSafeArrayOutArg(aValues));
1175
1176 return S_OK;
1177}
1178
1179/**
1180 * Public method implementation.
1181 * @return
1182 */
1183STDMETHODIMP VirtualSystemDescription::SetFinalValues(ComSafeArrayIn(BOOL, aEnabled),
1184 ComSafeArrayIn(IN_BSTR, argVboxValues),
1185 ComSafeArrayIn(IN_BSTR, argExtraConfigValues))
1186{
1187#ifndef RT_OS_WINDOWS
1188 NOREF(aEnabledSize);
1189#endif /* RT_OS_WINDOWS */
1190
1191 CheckComArgSafeArrayNotNull(aEnabled);
1192 CheckComArgSafeArrayNotNull(argVboxValues);
1193 CheckComArgSafeArrayNotNull(argExtraConfigValues);
1194
1195 AutoCaller autoCaller(this);
1196 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1197
1198 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1199
1200 com::SafeArray<BOOL> sfaEnabled(ComSafeArrayInArg(aEnabled));
1201 com::SafeArray<IN_BSTR> sfaVboxValues(ComSafeArrayInArg(argVboxValues));
1202 com::SafeArray<IN_BSTR> sfaExtraConfigValues(ComSafeArrayInArg(argExtraConfigValues));
1203
1204 if ( (sfaEnabled.size() != m->llDescriptions.size())
1205 || (sfaVboxValues.size() != m->llDescriptions.size())
1206 || (sfaExtraConfigValues.size() != m->llDescriptions.size())
1207 )
1208 return E_INVALIDARG;
1209
1210 list<VirtualSystemDescriptionEntry>::iterator it;
1211 size_t i = 0;
1212 for (it = m->llDescriptions.begin();
1213 it != m->llDescriptions.end();
1214 ++it, ++i)
1215 {
1216 VirtualSystemDescriptionEntry& vsde = *it;
1217
1218 if (sfaEnabled[i])
1219 {
1220 vsde.strVbox = sfaVboxValues[i];
1221 vsde.strExtraConfig = sfaExtraConfigValues[i];
1222 }
1223 else
1224 vsde.type = VirtualSystemDescriptionType_Ignore;
1225 }
1226
1227 return S_OK;
1228}
1229
1230/**
1231 * Public method implementation.
1232 * @return
1233 */
1234STDMETHODIMP VirtualSystemDescription::AddDescription(VirtualSystemDescriptionType_T aType,
1235 IN_BSTR aVboxValue,
1236 IN_BSTR aExtraConfigValue)
1237{
1238 AutoCaller autoCaller(this);
1239 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1240
1241 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1242
1243 addEntry(aType, "", aVboxValue, aVboxValue, 0, aExtraConfigValue);
1244
1245 return S_OK;
1246}
1247
1248/**
1249 * Internal method; adds a new description item to the member list.
1250 * @param aType Type of description for the new item.
1251 * @param strRef Reference item; only used with hard disk controllers.
1252 * @param aOrigValue Corresponding original value from OVF.
1253 * @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
1254 * @param ulSizeMB Weight for IProgress
1255 * @param strExtraConfig Extra configuration; meaning dependent on type.
1256 */
1257void VirtualSystemDescription::addEntry(VirtualSystemDescriptionType_T aType,
1258 const Utf8Str &strRef,
1259 const Utf8Str &aOrigValue,
1260 const Utf8Str &aAutoValue,
1261 uint32_t ulSizeMB,
1262 const Utf8Str &strExtraConfig /*= ""*/)
1263{
1264 VirtualSystemDescriptionEntry vsde;
1265 vsde.ulIndex = (uint32_t)m->llDescriptions.size(); // each entry gets an index so the client side can reference them
1266 vsde.type = aType;
1267 vsde.strRef = strRef;
1268 vsde.strOvf = aOrigValue;
1269 vsde.strVbox = aAutoValue;
1270 vsde.strExtraConfig = strExtraConfig;
1271 vsde.ulSizeMB = ulSizeMB;
1272
1273 m->llDescriptions.push_back(vsde);
1274}
1275
1276/**
1277 * Private method; returns a list of description items containing all the items from the member
1278 * description items of this virtual system that match the given type.
1279 * @param aType
1280 * @return
1281 */
1282std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
1283{
1284 std::list<VirtualSystemDescriptionEntry*> vsd;
1285
1286 list<VirtualSystemDescriptionEntry>::iterator it;
1287 for (it = m->llDescriptions.begin();
1288 it != m->llDescriptions.end();
1289 ++it)
1290 {
1291 if (it->type == aType)
1292 vsd.push_back(&(*it));
1293 }
1294
1295 return vsd;
1296}
1297
1298/**
1299 * Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
1300 * the given reference ID. Useful when needing the controller for a particular
1301 * virtual disk.
1302 * @param id
1303 * @return
1304 */
1305const VirtualSystemDescriptionEntry* VirtualSystemDescription::findControllerFromID(uint32_t id)
1306{
1307 Utf8Str strRef = Utf8StrFmt("%RI32", id);
1308 list<VirtualSystemDescriptionEntry>::const_iterator it;
1309 for (it = m->llDescriptions.begin();
1310 it != m->llDescriptions.end();
1311 ++it)
1312 {
1313 const VirtualSystemDescriptionEntry &d = *it;
1314 switch (d.type)
1315 {
1316 case VirtualSystemDescriptionType_HardDiskControllerIDE:
1317 case VirtualSystemDescriptionType_HardDiskControllerSATA:
1318 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
1319 if (d.strRef == strRef)
1320 return &d;
1321 break;
1322 }
1323 }
1324
1325 return NULL;
1326}
1327
1328/**
1329 * Method called from Appliance::Interpret() if the source OVF for a virtual system
1330 * contains a <vbox:Machine> element. This method then attempts to parse that and
1331 * create a MachineConfigFile instance from it which is stored in this instance data
1332 * and can then be used to create a machine.
1333 *
1334 * This must only be called once per instance.
1335 *
1336 * This rethrows all XML and logic errors from MachineConfigFile.
1337 *
1338 * @param elmMachine <vbox:Machine> element with attributes and subelements from some
1339 * DOM tree.
1340 */
1341void VirtualSystemDescription::importVboxMachineXML(const xml::ElementNode &elmMachine)
1342{
1343 settings::MachineConfigFile *pConfig = NULL;
1344
1345 Assert(m->pConfig == NULL);
1346
1347 try
1348 {
1349 pConfig = new settings::MachineConfigFile(NULL);
1350 pConfig->importMachineXML(elmMachine);
1351
1352 m->pConfig = pConfig;
1353 }
1354 catch (...)
1355 {
1356 if (pConfig)
1357 delete pConfig;
1358 throw;
1359 }
1360}
1361
1362/**
1363 * Returns the machine config created by importVboxMachineXML() or NULL if there's none.
1364 * @return
1365 */
1366const settings::MachineConfigFile* VirtualSystemDescription::getMachineConfig() const
1367{
1368 return m->pConfig;
1369}
1370
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